diff --git a/finance/src/integration-test/kotlin/net/corda/finance/flows/CashSelectionTest.kt b/finance/src/integration-test/kotlin/net/corda/finance/flows/CashSelectionTest.kt index bf055a3fa4..5e36c4705a 100644 --- a/finance/src/integration-test/kotlin/net/corda/finance/flows/CashSelectionTest.kt +++ b/finance/src/integration-test/kotlin/net/corda/finance/flows/CashSelectionTest.kt @@ -1,14 +1,16 @@ package net.corda.finance.flows +import net.corda.core.contracts.* +import net.corda.core.identity.Party import net.corda.core.messaging.startFlow +import net.corda.core.transactions.TransactionBuilder import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.finance.DOLLARS +import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.getCashBalance -import net.corda.testing.core.ALICE_NAME -import net.corda.testing.core.BOB_NAME -import net.corda.testing.core.DUMMY_BANK_A_NAME -import net.corda.testing.core.DUMMY_NOTARY_NAME +import net.corda.finance.issuedBy +import net.corda.testing.core.* import net.corda.testing.driver.DriverParameters import net.corda.testing.driver.driver import net.corda.testing.driver.internal.InProcessImpl @@ -48,4 +50,37 @@ class CashSelectionTest : IntegrationTest() { assertThat(availableBalanceAfterExit).isEqualTo(issuedAmount - exitedAmount) } } + + @Test + fun `select cash states issued by single transaction and give change`() { + driver(DriverParameters(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.finance"))) { + val node = startNode().getOrThrow() as InProcessImpl + val nodeIdentity = node.services.myInfo.singleIdentity() + + val coins = listOf(3.DOLLARS, 2.DOLLARS, 1.DOLLARS).map { it.issuedBy(nodeIdentity.ref(1)) } + + //create single transaction with 3 cash outputs + val issuance = TransactionBuilder(null as Party?) + coins.map { issuance.addOutputState(TransactionState(Cash.State(it, nodeIdentity), "net.corda.finance.contracts.asset.Cash", defaultNotaryIdentity)) } + issuance.addCommand(Cash.Commands.Issue(), nodeIdentity.owningKey) + + val transaction = node.services.signInitialTransaction(issuance, nodeIdentity.owningKey) + node.database.transaction { + node.services.recordTransactions(transaction) + } + + val issuedAmount = coins.reduce { sum, element -> sum + element }.withoutIssuer() + + val availableBalance = node.rpc.getCashBalance(issuedAmount.token) + + assertThat(availableBalance).isEqualTo(issuedAmount) + + val exitedAmount = 3.01.DOLLARS + node.rpc.startFlow(::CashExitFlow, exitedAmount, OpaqueBytes.of(1)).returnValue.getOrThrow() + + val availableBalanceAfterExit = node.rpc.getCashBalance(issuedAmount.token) + + assertThat(availableBalanceAfterExit).isEqualTo(issuedAmount - exitedAmount) + } + } } \ No newline at end of file diff --git a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionOracleImpl.kt b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionOracleImpl.kt index bf9e6170b4..99481385fd 100644 --- a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionOracleImpl.kt +++ b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionOracleImpl.kt @@ -40,7 +40,7 @@ class CashSelectionOracleImpl : AbstractCashSelection(maxRetries = 16, retrySlee WITH entry(transaction_id, output_index, pennies, total, lock_id) AS ( SELECT vs.transaction_id, vs.output_index, ccs.pennies, - SUM(ccs.pennies) OVER (ORDER BY ccs.transaction_id), vs.lock_id + SUM(ccs.pennies) OVER (ORDER BY ccs.transaction_id, ccs.output_index), vs.lock_id FROM contract_cash_states ccs, vault_states vs WHERE vs.transaction_id = ccs.transaction_id AND vs.output_index = ccs.output_index AND vs.state_status = 0 diff --git a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionSQLServerImpl.kt b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionSQLServerImpl.kt index 20d0c5343b..609822073d 100644 --- a/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionSQLServerImpl.kt +++ b/finance/src/main/kotlin/net/corda/finance/contracts/asset/cash/selection/CashSelectionSQLServerImpl.kt @@ -46,7 +46,7 @@ class CashSelectionSQLServerImpl : AbstractCashSelection(maxRetries = 16, retryS WITH row(transaction_id, output_index, pennies, total, lock_id) AS ( SELECT vs.transaction_id, vs.output_index, ccs.pennies, - SUM(ccs.pennies) OVER (ORDER BY ccs.transaction_id RANGE UNBOUNDED PRECEDING), vs.lock_id + SUM(ccs.pennies) OVER (ORDER BY ccs.transaction_id, ccs.output_index RANGE UNBOUNDED PRECEDING), vs.lock_id FROM contract_cash_states AS ccs, vault_states AS vs WHERE vs.transaction_id = ccs.transaction_id AND vs.output_index = ccs.output_index AND vs.state_status = 0