diff --git a/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt b/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt index dcc2897ad0..dea478ecc6 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/FungibleAsset.kt @@ -3,8 +3,6 @@ package net.corda.core.contracts import net.corda.core.flows.FlowException import net.corda.core.identity.AbstractParty import java.security.PublicKey -import net.corda.core.contracts.Amount.Companion.sumOrNull -import net.corda.core.contracts.Amount.Companion.sumOrZero class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException("Insufficient balance, missing $amountMissing") @@ -16,40 +14,28 @@ class InsufficientBalanceException(val amountMissing: Amount<*>) : FlowException * crude are fungible and countable (oil from two small containers can be poured into one large * container), shares of the same class in a specific company are fungible and countable, and so on. * - * See [Cash] for an example contract that implements currency using state objects that implement + * An example usage would be a cash transaction contract that implements currency using state objects that implement * this interface. * * @param T a type that represents the asset in question. This should describe the basic type of the asset * (GBP, USD, oil, shares in company , etc.) and any additional metadata (issuer, grade, class, etc.). */ interface FungibleAsset : OwnableState { + /** + * Amount represents a positive quantity of some issued product which can be cash, tokens, assets, or generally + * anything else that's quantifiable with integer quantities. See [Issued] and [Amount] for more details. + */ val amount: Amount> + /** * There must be an ExitCommand signed by these keys to destroy the amount. While all states require their * owner to sign, some (i.e. cash) also require the issuer. */ val exitKeys: Collection - /** There must be a MoveCommand signed by this key to claim the amount */ - override val owner: AbstractParty - fun move(newAmount: Amount>, newOwner: AbstractParty): FungibleAsset - - // Just for grouping - interface Commands : CommandData { - interface Move : MoveCommand, Commands - - /** - * Allows new asset states to be issued into existence: the nonce ("number used once") ensures the transaction - * has a unique ID even when there are no inputs. - */ - interface Issue : IssueCommand, Commands - - /** - * A command stating that money has been withdrawn from the shared ledger and is now accounted for - * in some other way. - */ - interface Exit : Commands { - val amount: Amount> - } - } + /** + * Copies the underlying data structure, replacing the amount and owner fields with the new values and leaving the + * rest (exitKeys) alone. + */ + fun withNewOwnerAndAmount(newAmount: Amount>, newOwner: AbstractParty): FungibleAsset } diff --git a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt index 1ac641576f..aef14de040 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/Structures.kt @@ -156,15 +156,15 @@ data class CommandAndState(val command: CommandData, val ownableState: OwnableSt * A contract state that can have a single owner. */ interface OwnableState : ContractState { - /** There must be a MoveCommand signed by this key to claim the amount */ + /** There must be a MoveCommand signed by this key to claim the amount. */ val owner: AbstractParty - /** Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone */ + /** Copies the underlying data structure, replacing the owner field with this new value and leaving the rest alone. */ fun withNewOwner(newOwner: AbstractParty): CommandAndState } // DOCEND 3 -/** Something which is scheduled to happen at a point in time */ +/** Something which is scheduled to happen at a point in time. */ interface Scheduled { val scheduledAt: Instant } @@ -284,12 +284,6 @@ data class Command(val value: T, val signers: List) override fun toString() = "${commandDataToString()} with pubkeys ${signers.joinToString()}" } -/** A common issue command, to enforce that issue commands have a nonce value. */ -// TODO: Revisit use of nonce values - should this be part of the TX rather than the command perhaps? -interface IssueCommand : CommandData { - val nonce: Long -} - /** A common move command for contract states which can change owner. */ interface MoveCommand : CommandData { /** diff --git a/core/src/test/kotlin/net/corda/core/contracts/LedgerTransactionQueryTests.kt b/core/src/test/kotlin/net/corda/core/contracts/LedgerTransactionQueryTests.kt index 71e71fe767..78e93f6b0e 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/LedgerTransactionQueryTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/LedgerTransactionQueryTests.kt @@ -28,6 +28,7 @@ class LedgerTransactionQueryTests : TestDependencyInjectionBase() { interface Commands { data class Cmd1(val id: Int) : CommandData, Commands data class Cmd2(val id: Int) : CommandData, Commands + data class Cmd3(val id: Int) : CommandData, Commands // Unused command, required for command not-present checks. } @@ -187,7 +188,7 @@ class LedgerTransactionQueryTests : TestDependencyInjectionBase() { val intCmd2 = ltx.commandsOfType() assertEquals(5, intCmd2.size) assertEquals(listOf(0, 1, 2, 3, 4), intCmd2.map { it.value.id }) - val notPresentQuery = ltx.commandsOfType(FungibleAsset.Commands.Exit::class.java) + val notPresentQuery = ltx.commandsOfType(Commands.Cmd3::class.java) assertEquals(emptyList(), notPresentQuery) } diff --git a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt index 296f1096cd..008706e2f9 100644 --- a/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt +++ b/core/src/test/kotlin/net/corda/core/flows/ContractUpgradeFlowTest.kt @@ -5,13 +5,13 @@ import net.corda.contracts.asset.Cash import net.corda.core.contracts.* import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party +import net.corda.core.internal.Emoji import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.startFlow import net.corda.core.node.services.queryBy -import net.corda.core.utilities.OpaqueBytes import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.SignedTransaction -import net.corda.core.internal.Emoji +import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow import net.corda.finance.USD import net.corda.finance.`issued by` @@ -203,7 +203,7 @@ class ContractUpgradeFlowTest { override val contract = CashV2() override val participants = owners - override fun move(newAmount: Amount>, newOwner: AbstractParty) = copy(amount = amount.copy(newAmount.quantity), owners = listOf(newOwner)) + override fun withNewOwnerAndAmount(newAmount: Amount>, newOwner: AbstractParty) = copy(amount = amount.copy(newAmount.quantity), owners = listOf(newOwner)) override fun toString() = "${Emoji.bagOfCash}New Cash($amount at ${amount.token.issuer} owned by $owner)" override fun withNewOwner(newOwner: AbstractParty) = CommandAndState(Cash.Commands.Move(), copy(owners = listOf(newOwner))) } diff --git a/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java b/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java index f4cec78f1c..b239f3776a 100644 --- a/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java +++ b/docs/source/example-code/src/main/java/net/corda/docs/FlowCookbookJava.java @@ -280,7 +280,7 @@ public class FlowCookbookJava { TypeOnlyCommandData typeOnlyCommandData = new DummyContract.Commands.Create(); // 2. Include additional data which can be used by the contract // during verification, alongside fulfilling the roles above - CommandData commandDataWithData = new Cash.Commands.Issue(12345678); + CommandData commandDataWithData = new Cash.Commands.Issue(); // Attachments are identified by their hash. // The attachment with the corresponding hash must have been diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt index b5522a22a1..398b35ccb8 100644 --- a/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/FlowCookbook.kt @@ -262,8 +262,8 @@ object FlowCookbook { // fork the contract's verification logic. val typeOnlyCommandData: TypeOnlyCommandData = DummyContract.Commands.Create() // 2. Include additional data which can be used by the contract - // during verification, alongside fulfilling the roles above - val commandDataWithData: CommandData = Cash.Commands.Issue(nonce = 12345678) + // during verification, alongside fulfilling the roles above. + val commandDataWithData: CommandData = Cash.Commands.Issue() // Attachments are identified by their hash. // The attachment with the corresponding hash must have been diff --git a/docs/source/using-a-notary.rst b/docs/source/using-a-notary.rst index 08517c6eaa..2c9f5c2fef 100644 --- a/docs/source/using-a-notary.rst +++ b/docs/source/using-a-notary.rst @@ -87,9 +87,9 @@ we just use a helper that handles it for us. We also assume that we already have .. sourcecode:: kotlin val inputState = StateAndRef(sate, stateRef) - val moveTransactionBuilder = DummyContract.move(inputState, newOwner = aliceParty.owningKey) + val moveTransactionBuilder = DummyContract.withNewOwnerAndAmount(inputState, newOwner = aliceParty.owningKey) -The ``DummyContract.move()`` method will a new transaction builder with our old state as the input, a new state +The ``DummyContract.withNewOwnerAndAmount()`` method will a new transaction builder with our old state as the input, a new state with Alice as the owner, and a relevant contract command for "move". Again we sign the transaction, and build it: diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt b/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt index 3416b764ab..b12ee11f75 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/Cash.kt @@ -6,7 +6,6 @@ import co.paralleluniverse.strands.Strand import net.corda.core.contracts.* import net.corda.core.crypto.SecureHash import net.corda.core.crypto.entropyToKeyPair -import net.corda.core.crypto.newSecureRandom import net.corda.core.crypto.testing.NULL_PARTY import net.corda.core.crypto.toBase58String import net.corda.core.identity.AbstractParty @@ -77,7 +76,7 @@ class Cash : OnLedgerAsset() { override val contract = CASH_PROGRAM_ID override val participants = listOf(owner) - override fun move(newAmount: Amount>, newOwner: AbstractParty): FungibleAsset + override fun withNewOwnerAndAmount(newAmount: Amount>, newOwner: AbstractParty): FungibleAsset = copy(amount = amount.copy(newAmount.quantity), owner = newOwner) override fun toString() = "${Emoji.bagOfCash}Cash($amount at ${amount.token.issuer} owned by $owner)" @@ -110,7 +109,7 @@ class Cash : OnLedgerAsset() { // DOCEND 1 // Just for grouping - interface Commands : FungibleAsset.Commands { + interface Commands : CommandData { /** * A command stating that money has been moved, optionally to fulfil another contract. * @@ -118,19 +117,18 @@ class Cash : OnLedgerAsset() { * should take the moved states into account when considering whether it is valid. Typically this will be * null. */ - data class Move(override val contract: Class? = null) : FungibleAsset.Commands.Move, Commands + data class Move(override val contract: Class? = null) : MoveCommand /** - * Allows new cash states to be issued into existence: the nonce ("number used once") ensures the transaction - * has a unique ID even when there are no inputs. + * Allows new cash states to be issued into existence. */ - data class Issue(override val nonce: Long = newSecureRandom().nextLong()) : FungibleAsset.Commands.Issue, Commands + class Issue : TypeOnlyCommandData() /** * A command stating that money has been withdrawn from the shared ledger and is now accounted for * in some other way. */ - data class Exit(override val amount: Amount>) : Commands, FungibleAsset.Commands.Exit + data class Exit(val amount: Amount>) : CommandData } /** @@ -143,13 +141,12 @@ class Cash : OnLedgerAsset() { * Puts together an issuance transaction for the specified amount that starts out being owned by the given pubkey. */ fun generateIssue(tx: TransactionBuilder, amount: Amount>, owner: AbstractParty, notary: Party) - = generateIssue(tx, TransactionState(State(amount, owner), notary), generateIssueCommand()) + = generateIssue(tx, TransactionState(State(amount, owner), notary), Commands.Issue()) override fun deriveState(txState: TransactionState, amount: Amount>, owner: AbstractParty) = txState.copy(data = txState.data.copy(amount = amount, owner = owner)) override fun generateExitCommand(amount: Amount>) = Commands.Exit(amount) - override fun generateIssueCommand() = Commands.Issue() override fun generateMoveCommand() = Commands.Move() override fun verify(tx: LedgerTransaction) { @@ -211,7 +208,6 @@ class Cash : OnLedgerAsset() { val outputAmount = outputs.sumCash() val cashCommands = tx.commands.select() requireThat { - "the issue command has a nonce" using (issueCommand.value.nonce != 0L) // TODO: This doesn't work with the trader demo, so use the underlying key instead // "output states are issued by a command signer" by (issuer.party in issueCommand.signingParties) "output states are issued by a command signer" using (issuer.party.owningKey in issueCommand.signers) diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt b/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt index 5b7bcb65f4..8b09e903cf 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/CommodityContract.kt @@ -2,18 +2,18 @@ package net.corda.contracts.asset import net.corda.contracts.Commodity import net.corda.core.contracts.* -import net.corda.core.crypto.newSecureRandom import net.corda.core.identity.AbstractParty import net.corda.core.identity.Party import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder -import java.security.PublicKey import net.corda.finance.utils.sumCommodities import net.corda.finance.utils.sumCommoditiesOrNull import net.corda.finance.utils.sumCommoditiesOrZero +import java.security.PublicKey import java.util.* + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Commodity @@ -48,7 +48,7 @@ class CommodityContract : OnLedgerAsset = Collections.singleton(owner.owningKey) override val participants = listOf(owner) - override fun move(newAmount: Amount>, newOwner: AbstractParty): FungibleAsset + override fun withNewOwnerAndAmount(newAmount: Amount>, newOwner: AbstractParty): FungibleAsset = copy(amount = amount.copy(newAmount.quantity), owner = newOwner) override fun toString() = "Commodity($amount at ${amount.token.issuer} owned by $owner)" @@ -58,7 +58,7 @@ class CommodityContract : OnLedgerAsset? = null) : FungibleAsset.Commands.Move, Commands + data class Move(override val contract: Class? = null) : MoveCommand /** - * Allows new commodity states to be issued into existence: the nonce ("number used once") ensures the transaction - * has a unique ID even when there are no inputs. + * Allows new commodity states to be issued into existence. */ - data class Issue(override val nonce: Long = newSecureRandom().nextLong()) : FungibleAsset.Commands.Issue, Commands + class Issue : TypeOnlyCommandData() /** * A command stating that money has been withdrawn from the shared ledger and is now accounted for * in some other way. */ - data class Exit(override val amount: Amount>) : Commands, FungibleAsset.Commands.Exit + data class Exit(val amount: Amount>) : CommandData } override fun verify(tx: LedgerTransaction) { @@ -140,7 +139,6 @@ class CommodityContract : OnLedgerAsset() requireThat { - "the issue command has a nonce" using (issueCommand.value.nonce != 0L) "output deposits are owned by a command signer" using (issuer.party in issueCommand.signingParties) "output values sum to more than the inputs" using (outputAmount > inputAmount) "there is only a single issue command" using (commodityCommands.count() == 1) @@ -160,13 +158,12 @@ class CommodityContract : OnLedgerAsset>, owner: AbstractParty, notary: Party) - = generateIssue(tx, TransactionState(State(amount, owner), notary), generateIssueCommand()) + = generateIssue(tx, TransactionState(State(amount, owner), notary), Commands.Issue()) override fun deriveState(txState: TransactionState, amount: Amount>, owner: AbstractParty) = txState.copy(data = txState.data.copy(amount = amount, owner = owner)) override fun generateExitCommand(amount: Amount>) = Commands.Exit(amount) - override fun generateIssueCommand() = Commands.Issue() override fun generateMoveCommand() = Commands.Move() -} \ No newline at end of file +} diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt b/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt index d34377caed..589695990d 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/Obligation.kt @@ -1,6 +1,5 @@ package net.corda.contracts.asset -import net.corda.core.internal.VisibleForTesting import net.corda.contracts.NetCommand import net.corda.contracts.NetType import net.corda.contracts.NettableState @@ -8,11 +7,11 @@ import net.corda.contracts.asset.Obligation.Lifecycle.NORMAL import net.corda.core.contracts.* import net.corda.core.crypto.SecureHash import net.corda.core.crypto.entropyToKeyPair -import net.corda.core.crypto.random63BitValue import net.corda.core.identity.AbstractParty import net.corda.core.identity.AnonymousParty import net.corda.core.identity.Party import net.corda.core.internal.Emoji +import net.corda.core.internal.VisibleForTesting import net.corda.core.serialization.CordaSerializable import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.TransactionBuilder @@ -140,7 +139,7 @@ class Obligation

: Contract { override val participants: List = listOf(obligor, beneficiary) override val owner: AbstractParty = beneficiary - override fun move(newAmount: Amount>>, newOwner: AbstractParty): State

+ override fun withNewOwnerAndAmount(newAmount: Amount>>, newOwner: AbstractParty): State

= copy(quantity = newAmount.quantity, beneficiary = newOwner) override fun toString() = when (lifecycle) { @@ -178,12 +177,12 @@ class Obligation

: Contract { // Just for grouping @CordaSerializable - interface Commands : FungibleAsset.Commands { + interface Commands : CommandData { /** * Net two or more obligation states together in a close-out netting style. Limited to bilateral netting * as only the beneficiary (not the obligor) needs to sign. */ - data class Net(override val type: NetType) : NetCommand, Commands + data class Net(override val type: NetType) : NetCommand /** * A command stating that a debt has been moved, optionally to fulfil another contract. @@ -192,26 +191,25 @@ class Obligation

: Contract { * should take the moved states into account when considering whether it is valid. Typically this will be * null. */ - data class Move(override val contract: Class? = null) : Commands, FungibleAsset.Commands.Move + data class Move(override val contract: Class? = null) : MoveCommand - /** - * Allows new obligation states to be issued into existence: the nonce ("number used once") ensures the - * transaction has a unique ID even when there are no inputs. + /** + * Allows new obligation states to be issued into existence. */ - data class Issue(override val nonce: Long = random63BitValue()) : FungibleAsset.Commands.Issue, Commands + class Issue : TypeOnlyCommandData() /** * A command stating that the obligor is settling some or all of the amount owed by transferring a suitable * state object to the beneficiary. If this reduces the balance to zero, the state object is destroyed. * @see [MoveCommand]. */ - data class Settle

(val amount: Amount>>) : Commands + data class Settle

(val amount: Amount>>) : CommandData /** * A command stating that the beneficiary is moving the contract into the defaulted state as it has not been settled * by the due date, or resetting a defaulted contract back to the issued state. */ - data class SetLifecycle(val lifecycle: Lifecycle) : Commands { + data class SetLifecycle(val lifecycle: Lifecycle) : CommandData { val inverse: Lifecycle get() = when (lifecycle) { Lifecycle.NORMAL -> Lifecycle.DEFAULTED @@ -223,7 +221,7 @@ class Obligation

: Contract { * A command stating that the debt is being released by the beneficiary. Normally would indicate * either settlement outside of the ledger, or that the obligor is unable to pay. */ - data class Exit

(override val amount: Amount>>) : Commands, FungibleAsset.Commands.Exit> + data class Exit

(val amount: Amount>>) : CommandData } override fun verify(tx: LedgerTransaction) { @@ -304,7 +302,6 @@ class Obligation

: Contract { val outputAmount = outputs.sumObligations

() val issueCommands = tx.commands.select() requireThat { - "the issue command has a nonce" using (issueCommand.value.nonce != 0L) "output states are issued by a command signer" using (issuer.party in issueCommand.signingParties) "output values sum to more than the inputs" using (outputAmount > inputAmount) "there is only a single issue command" using (issueCommands.count() == 1) @@ -510,7 +507,7 @@ class Obligation

: Contract { fun generateExit(tx: TransactionBuilder, amountIssued: Amount>>, assetStates: List>>): Set = OnLedgerAsset.generateExit(tx, amountIssued, assetStates, - deriveState = { state, amount, owner -> state.copy(data = state.data.move(amount, owner)) }, + deriveState = { state, amount, owner -> state.copy(data = state.data.withNewOwnerAndAmount(amount, owner)) }, generateMoveCommand = { -> Commands.Move() }, generateExitCommand = { amount -> Commands.Exit(amount) } ) @@ -673,13 +670,13 @@ class Obligation

: Contract { val assetState = ref.state.data val amount = Amount(assetState.amount.quantity, assetState.amount.token.product) if (obligationRemaining >= amount) { - tx.addOutputState(assetState.move(assetState.amount, obligationOwner), notary) + tx.addOutputState(assetState.withNewOwnerAndAmount(assetState.amount, obligationOwner), notary) obligationRemaining -= amount } else { val change = Amount(obligationRemaining.quantity, assetState.amount.token) // Split the state in two, sending the change back to the previous beneficiary - tx.addOutputState(assetState.move(change, obligationOwner), notary) - tx.addOutputState(assetState.move(assetState.amount - change, assetState.owner), notary) + tx.addOutputState(assetState.withNewOwnerAndAmount(change, obligationOwner), notary) + tx.addOutputState(assetState.withNewOwnerAndAmount(assetState.amount - change, assetState.owner), notary) obligationRemaining -= Amount(0L, obligationRemaining.token) } assetSigners.add(assetState.owner) diff --git a/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt b/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt index 050d3a86da..86a986e28f 100644 --- a/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt +++ b/finance/src/main/kotlin/net/corda/contracts/asset/OnLedgerAsset.kt @@ -244,9 +244,8 @@ abstract class OnLedgerAsset> : C ) } - abstract fun generateExitCommand(amount: Amount>): FungibleAsset.Commands.Exit - abstract fun generateIssueCommand(): FungibleAsset.Commands.Issue - abstract fun generateMoveCommand(): FungibleAsset.Commands.Move + abstract fun generateExitCommand(amount: Amount>): CommandData + abstract fun generateMoveCommand(): MoveCommand /** * Derive a new transaction state based on the given example, with amount and owner modified. This allows concrete diff --git a/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt b/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt index 30ddb30f1b..c2baf728c9 100644 --- a/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/asset/CashTests.kt @@ -143,10 +143,6 @@ class CashTests : TestDependencyInjectionBase() { owner = AnonymousParty(ALICE_PUBKEY) ) } - tweak { - command(MINI_CORP_PUBKEY) { Cash.Commands.Issue(0) } - this `fails with` "has a nonce" - } command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } this.verifies() } diff --git a/finance/src/test/kotlin/net/corda/contracts/DummyFungibleContract.kt b/finance/src/test/kotlin/net/corda/contracts/asset/DummyFungibleContract.kt similarity index 87% rename from finance/src/test/kotlin/net/corda/contracts/DummyFungibleContract.kt rename to finance/src/test/kotlin/net/corda/contracts/asset/DummyFungibleContract.kt index 5d93827b6e..807ccb0665 100644 --- a/finance/src/test/kotlin/net/corda/contracts/DummyFungibleContract.kt +++ b/finance/src/test/kotlin/net/corda/contracts/asset/DummyFungibleContract.kt @@ -1,16 +1,13 @@ package net.corda.contracts.asset import net.corda.core.contracts.* -import net.corda.core.crypto.newSecureRandom import net.corda.core.crypto.toBase58String import net.corda.core.identity.AbstractParty -import net.corda.core.identity.Party import net.corda.core.internal.Emoji import net.corda.core.schemas.MappedSchema import net.corda.core.schemas.PersistentState import net.corda.core.schemas.QueryableState import net.corda.core.transactions.LedgerTransaction -import net.corda.core.transactions.TransactionBuilder import net.corda.finance.utils.sumCash import net.corda.finance.utils.sumCashOrNull import net.corda.finance.utils.sumCashOrZero @@ -36,7 +33,7 @@ class DummyFungibleContract : OnLedgerAsset>, newOwner: AbstractParty): FungibleAsset + override fun withNewOwnerAndAmount(newAmount: Amount>, newOwner: AbstractParty): FungibleAsset = copy(amount = amount.copy(newAmount.quantity), owner = newOwner) override fun toString() = "${Emoji.bagOfCash}Cash($amount at ${amount.token.issuer} owned by $owner)" @@ -77,26 +74,19 @@ class DummyFungibleContract : OnLedgerAsset = listOf(SampleCashSchemaV1, SampleCashSchemaV2, SampleCashSchemaV3) } - interface Commands : FungibleAsset.Commands { + interface Commands : CommandData { - data class Move(override val contract: Class? = null) : FungibleAsset.Commands.Move, Commands + data class Move(override val contract: Class? = null) : MoveCommand - data class Issue(override val nonce: Long = newSecureRandom().nextLong()) : FungibleAsset.Commands.Issue, Commands + class Issue : TypeOnlyCommandData() - data class Exit(override val amount: Amount>) : Commands, FungibleAsset.Commands.Exit + data class Exit(val amount: Amount>) : CommandData } - fun generateIssue(tx: TransactionBuilder, tokenDef: Issued, pennies: Long, owner: AbstractParty, notary: Party) - = generateIssue(tx, Amount(pennies, tokenDef), owner, notary) - - fun generateIssue(tx: TransactionBuilder, amount: Amount>, owner: AbstractParty, notary: Party) - = generateIssue(tx, TransactionState(State(amount, owner), notary), generateIssueCommand()) - override fun deriveState(txState: TransactionState, amount: Amount>, owner: AbstractParty) = txState.copy(data = txState.data.copy(amount = amount, owner = owner)) override fun generateExitCommand(amount: Amount>) = Commands.Exit(amount) - override fun generateIssueCommand() = Commands.Issue() override fun generateMoveCommand() = Commands.Move() override fun verify(tx: LedgerTransaction) { @@ -155,7 +145,6 @@ class DummyFungibleContract : OnLedgerAsset() requireThat { - "the issue command has a nonce" using (issueCommand.value.nonce != 0L) // TODO: This doesn't work with the trader demo, so use the underlying key instead // "output states are issued by a command signer" by (issuer.party in issueCommand.signingParties) "output states are issued by a command signer" using (issuer.party.owningKey in issueCommand.signers) diff --git a/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt b/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt index e285f325f0..256b291855 100644 --- a/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt +++ b/finance/src/test/kotlin/net/corda/contracts/asset/ObligationTests.kt @@ -129,10 +129,6 @@ class ObligationTests { template = megaCorpDollarSettlement ) } - tweak { - command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue(0) } - this `fails with` "has a nonce" - } command(MINI_CORP_PUBKEY) { Obligation.Commands.Issue() } this.verifies() } @@ -189,7 +185,7 @@ class ObligationTests { this `fails with` "" } - // Can't have any other commands if we have an issue command (because the issue command overrules them) + // Can't have any other commands if we have an issue command (because the issue command overrules them). transaction { input { inState } output { inState.copy(quantity = inState.amount.quantity * 2) }