diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt b/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt index aa3a952b82..2d15cebd7e 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/cash/Cash.kt @@ -62,6 +62,9 @@ class Cash : FungibleAsset() { override val participants: List get() = listOf(owner) + override fun move(amount: Amount>, owner: PublicKey): FungibleAsset.State + = copy(amount = amount, owner = owner) + override fun toString() = "${Emoji.bagOfCash}Cash($amount at $deposit owned by ${owner.toStringShort()})" override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt index 145ef9b0b8..56061adab2 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAsset.kt @@ -31,9 +31,9 @@ class InsufficientBalanceException(val amountMissing: Amount) : Except */ abstract class FungibleAsset : Contract { /** A state representing a cash claim against some party */ - interface State : FungibleAssetState { + interface State : FungibleAssetState> { /** Where the underlying currency backing this ledger entry can be found (propagated) */ - override val deposit: PartyAndReference + val deposit: PartyAndReference override val amount: Amount> /** There must be a MoveCommand signed by this key to claim the amount */ override val owner: PublicKey diff --git a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt index e98cfdbe9e..17fa51adb2 100644 --- a/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt +++ b/contracts/src/main/kotlin/com/r3corda/contracts/cash/FungibleAssetState.kt @@ -1,16 +1,15 @@ package com.r3corda.contracts.cash import com.r3corda.core.contracts.Amount -import com.r3corda.core.contracts.OwnableState -import com.r3corda.core.contracts.PartyAndReference import com.r3corda.core.contracts.Issued +import com.r3corda.core.contracts.OwnableState +import java.security.PublicKey /** * Common elements of cash contract states. */ -interface FungibleAssetState : OwnableState { - val issuanceDef: Issued - /** Where the underlying currency backing this ledger entry can be found (propagated) */ - val deposit: PartyAndReference +interface FungibleAssetState : OwnableState { + val issuanceDef: I val amount: Amount> + fun move(amount: Amount>, owner: PublicKey): FungibleAssetState } \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt index 834fa36dda..4e36dc0d69 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/ContractsDSL.kt @@ -30,7 +30,7 @@ val Int.SWISS_FRANCS: Amount get() = Amount(this.toLong() * 100, CHF) val Double.DOLLARS: Amount get() = Amount((this * 100).toLong(), USD) infix fun Currency.`issued by`(deposit: PartyAndReference) : Issued = Issued(deposit, this) -infix fun Amount.`issued by`(deposit: PartyAndReference) : Amount> = Amount(quantity, token `issued by` deposit) +infix fun Amount.`issued by`(deposit: PartyAndReference) : Amount> = Amount(quantity, Issued(deposit, this.token)) //// Requirements ///////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt index dc67723d25..49c9a5a441 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/FinanceTypes.kt @@ -399,3 +399,24 @@ fun calculateDaysBetween(startDate: LocalDate, else -> TODO("Can't calculate days using convention $dcbDay / $dcbYear") } } + +/** + * Enum for the types of netting that can be applied to state objects. Exact behaviour + * for each type of netting is left to the contract to determine. + */ +enum class NetType { + /** + * Close-out netting applies where one party is bankrupt or otherwise defaults (exact terms are contract specific), + * and allows their counterparty to net obligations without requiring approval from all parties. For example, if + * Bank A owes Bank B £1m, and Bank B owes Bank A £1m, in the case of Bank B defaulting this would enable Bank A + * to net out the two obligations to zero, rather than being legally obliged to pay £1m without any realistic + * expectation of the debt to them being paid. Realistically this is limited to bilateral netting, to simplify + * determining which party must sign the netting transaction. + */ + CLOSE_OUT, + /** + * "Payment" is used to refer to conventional netting, where all parties must confirm the netting transaction. This + * can be a multilateral netting transaction, and may be created by a central clearing service. + */ + PAYMENT +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt index 0c997f8ccc..66ffcb817c 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt @@ -18,6 +18,23 @@ interface NamedByHash { val id: SecureHash } +/** + * Interface for state objects that support being netted with other state objects. + */ +interface BilateralNettableState> { + /** + * Returns an object used to determine if two states can be subject to close-out netting. If two states return + * equal objects, they can be close out netted together. + */ + val bilateralNetState: Any + + /** + * Perform bilateral netting of this state with another state. The two states must be compatible (as in + * bilateralNetState objects are equal). + */ + fun net(other: T): T +} + /** * A contract state (or just "state") contains opaque data used by a contract program. It can be thought of as a disk * file that the program can use to persist data across transactions. States are immutable: once created they are never @@ -233,6 +250,7 @@ data class Command(val value: CommandData, val signers: List) { } /** 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 }