mirror of
https://github.com/corda/corda.git
synced 2024-12-19 21:17:58 +00:00
Replace 'by' with 'using' to avoid overloading Kotlin keyword in contracts DSL. Deprecates 'by' with offered replacement.
This commit is contained in:
parent
36d5d0d7b2
commit
108f171e03
@ -57,9 +57,16 @@ infix fun Amount<Currency>.issuedBy(deposit: PartyAndReference) = Amount(quantit
|
||||
|
||||
object Requirements {
|
||||
@Suppress("NOTHING_TO_INLINE") // Inlining this takes it out of our committed ABI.
|
||||
infix inline fun String.by(expr: Boolean) {
|
||||
infix inline fun String.using(expr: Boolean) {
|
||||
if (!expr) throw IllegalArgumentException("Failed requirement: $this")
|
||||
}
|
||||
// Avoid overloading Kotlin keywords
|
||||
@Deprecated("This function is deprecated, use 'using' instead",
|
||||
ReplaceWith("using (expr)", "net.corda.core.contracts.Requirements.using"))
|
||||
@Suppress("NOTHING_TO_INLINE") // Inlining this takes it out of our committed ABI.
|
||||
infix inline fun String.by(expr: Boolean) {
|
||||
using(expr)
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <R> requireThat(body: Requirements.() -> R) = Requirements.body()
|
||||
@ -124,7 +131,7 @@ inline fun <reified T : MoveCommand> verifyMoveCommand(inputs: List<OwnableState
|
||||
val command = commands.requireSingleCommand<T>()
|
||||
val keysThatSigned = command.signers.toSet()
|
||||
requireThat {
|
||||
"the owning keys are a subset of the signing keys" by keysThatSigned.containsAll(owningPubKeys)
|
||||
"the owning keys are a subset of the signing keys" using keysThatSigned.containsAll(owningPubKeys)
|
||||
}
|
||||
return command.value
|
||||
}
|
||||
|
@ -252,8 +252,8 @@ interface LinearState : ContractState {
|
||||
val inputIds = inputs.map { it.linearId }.distinct()
|
||||
val outputIds = outputs.map { it.linearId }.distinct()
|
||||
requireThat {
|
||||
"LinearStates are not merged" by (inputIds.count() == inputs.count())
|
||||
"LinearStates are not split" by (outputIds.count() == outputs.count())
|
||||
"LinearStates are not merged" using (inputIds.count() == inputs.count())
|
||||
"LinearStates are not split" using (outputIds.count() == outputs.count())
|
||||
}
|
||||
return emptySet()
|
||||
}
|
||||
|
@ -33,10 +33,10 @@ object ContractUpgradeFlow {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val upgradedContract = command.upgradedContractClass.newInstance() as UpgradedContract<ContractState, *>
|
||||
requireThat {
|
||||
"The signing keys include all participant keys" by keysThatSigned.containsAll(participants)
|
||||
"Inputs state reference the legacy contract" by (input.contract.javaClass == upgradedContract.legacyContract)
|
||||
"Outputs state reference the upgraded contract" by (output.contract.javaClass == command.upgradedContractClass)
|
||||
"Output state must be an upgraded version of the input state" by (output == upgradedContract.upgrade(input))
|
||||
"The signing keys include all participant keys" using keysThatSigned.containsAll(participants)
|
||||
"Inputs state reference the legacy contract" using (input.contract.javaClass == upgradedContract.legacyContract)
|
||||
"Outputs state reference the upgraded contract" using (output.contract.javaClass == command.upgradedContractClass)
|
||||
"Output state must be an upgraded version of the input state" using (output == upgradedContract.upgrade(input))
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,9 +74,9 @@ object ContractUpgradeFlow {
|
||||
val proposedTx = proposal.stx.tx
|
||||
val expectedTx = assembleBareTx(oldStateAndRef, proposal.modification).toWireTransaction()
|
||||
requireThat {
|
||||
"The instigator is one of the participants" by oldStateAndRef.state.data.participants.contains(otherSide.owningKey)
|
||||
"The proposed upgrade ${proposal.modification.javaClass} is a trusted upgrade path" by (proposal.modification == authorisedUpgrade)
|
||||
"The proposed tx matches the expected tx for this upgrade" by (proposedTx == expectedTx)
|
||||
"The instigator is one of the participants" using oldStateAndRef.state.data.participants.contains(otherSide.owningKey)
|
||||
"The proposed upgrade ${proposal.modification.javaClass} is a trusted upgrade path" using (proposal.modification == authorisedUpgrade)
|
||||
"The proposed tx matches the expected tx for this upgrade" using (proposedTx == expectedTx)
|
||||
}
|
||||
ContractUpgradeFlow.verify(oldStateAndRef.state.data, expectedTx.outRef<ContractState>(0).state.data, expectedTx.commands.single())
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ class TransactionEncumbranceTests {
|
||||
val timeLockInput = tx.inputs.filterIsInstance<State>().singleOrNull() ?: return
|
||||
val time = tx.timestamp?.before ?: throw IllegalArgumentException("Transactions containing time-locks must be timestamped")
|
||||
requireThat {
|
||||
"the time specified in the time-lock has passed" by (time >= timeLockInput.validFrom)
|
||||
"the time specified in the time-lock has passed" using (time >= timeLockInput.validFrom)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,13 +79,13 @@ data class TradeApprovalContract(override val legalContractReference: SecureHash
|
||||
when (command.value) {
|
||||
is Commands.Issue -> {
|
||||
requireThat {
|
||||
"Issue of new WorkflowContract must not include any inputs" by (tx.inputs.isEmpty())
|
||||
"Issue of new WorkflowContract must be in a unique transaction" by (tx.outputs.size == 1)
|
||||
"Issue of new WorkflowContract must not include any inputs" using (tx.inputs.isEmpty())
|
||||
"Issue of new WorkflowContract must be in a unique transaction" using (tx.outputs.size == 1)
|
||||
}
|
||||
val issued = tx.outputs.get(0) as TradeApprovalContract.State
|
||||
requireThat {
|
||||
"Issue requires the source Party as signer" by (command.signers.contains(issued.source.owningKey))
|
||||
"Initial Issue state must be NEW" by (issued.state == WorkflowState.NEW)
|
||||
"Issue requires the source Party as signer" using (command.signers.contains(issued.source.owningKey))
|
||||
"Initial Issue state must be NEW" using (issued.state == WorkflowState.NEW)
|
||||
}
|
||||
}
|
||||
is Commands.Completed -> {
|
||||
@ -95,11 +95,11 @@ data class TradeApprovalContract(override val legalContractReference: SecureHash
|
||||
val before = group.inputs.single()
|
||||
val after = group.outputs.single()
|
||||
requireThat {
|
||||
"Only a non-final trade can be modified" by (before.state == WorkflowState.NEW)
|
||||
"Output must be a final state" by (after.state in setOf(WorkflowState.APPROVED, WorkflowState.REJECTED))
|
||||
"Completed command can only change state" by (before == after.copy(state = before.state))
|
||||
"Completed command requires the source Party as signer" by (command.signers.contains(before.source.owningKey))
|
||||
"Completed command requires the counterparty as signer" by (command.signers.contains(before.counterparty.owningKey))
|
||||
"Only a non-final trade can be modified" using (before.state == WorkflowState.NEW)
|
||||
"Output must be a final state" using (after.state in setOf(WorkflowState.APPROVED, WorkflowState.REJECTED))
|
||||
"Completed command can only change state" using (before == after.copy(state = before.state))
|
||||
"Completed command requires the source Party as signer" using (command.signers.contains(before.source.owningKey))
|
||||
"Completed command requires the counterparty as signer" using (command.signers.contains(before.counterparty.owningKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class UniversalContract : Contract {
|
||||
}
|
||||
}
|
||||
is Fixing -> {
|
||||
requireThat { "Fixing must be included" by false }
|
||||
requireThat { "Fixing must be included" using false }
|
||||
0.0.bd
|
||||
}
|
||||
is Interest -> {
|
||||
@ -95,7 +95,7 @@ class UniversalContract : Contract {
|
||||
fun validateImmediateTransfers(tx: TransactionForContract, arrangement: Arrangement): Arrangement = when (arrangement) {
|
||||
is Obligation -> {
|
||||
val amount = eval(tx, arrangement.amount)
|
||||
requireThat { "transferred quantity is non-negative" by (amount >= BigDecimal.ZERO) }
|
||||
requireThat { "transferred quantity is non-negative" using (amount >= BigDecimal.ZERO) }
|
||||
Obligation(const(amount), arrangement.currency, arrangement.from, arrangement.to)
|
||||
}
|
||||
is And -> And(arrangement.arrangements.map { validateImmediateTransfers(tx, it) }.toSet())
|
||||
@ -180,7 +180,7 @@ class UniversalContract : Contract {
|
||||
override fun verify(tx: TransactionForContract) {
|
||||
|
||||
requireThat {
|
||||
"transaction has a single command".by(tx.commands.size == 1)
|
||||
"transaction has a single command".using(tx.commands.size == 1)
|
||||
}
|
||||
|
||||
val cmd = tx.commands.requireSingleCommand<UniversalContract.Commands>()
|
||||
@ -207,10 +207,10 @@ class UniversalContract : Contract {
|
||||
assert(rest is Zero)
|
||||
|
||||
requireThat {
|
||||
"action must be timestamped" by (tx.timestamp != null)
|
||||
"action must be timestamped" using (tx.timestamp != null)
|
||||
// "action must be authorized" by (cmd.signers.any { action.actors.any { party -> party.owningKey == it } })
|
||||
// todo perhaps merge these two requirements?
|
||||
"condition must be met" by (eval(tx, action.condition))
|
||||
"condition must be met" using (eval(tx, action.condition))
|
||||
}
|
||||
|
||||
// verify that any resulting transfers can be resolved
|
||||
@ -221,8 +221,8 @@ class UniversalContract : Contract {
|
||||
1 -> {
|
||||
val outState = tx.outputs.single() as State
|
||||
requireThat {
|
||||
"output state must match action result state" by (arrangement.equals(outState.details))
|
||||
"output state must match action result state" by (rest == zero)
|
||||
"output state must match action result state" using (arrangement.equals(outState.details))
|
||||
"output state must match action result state" using (rest == zero)
|
||||
}
|
||||
}
|
||||
0 -> throw IllegalArgumentException("must have at least one out state")
|
||||
@ -230,7 +230,7 @@ class UniversalContract : Contract {
|
||||
val allContracts = And(tx.outputs.map { (it as State).details }.toSet())
|
||||
|
||||
requireThat {
|
||||
"output states must match action result state" by (arrangement.equals(allContracts))
|
||||
"output states must match action result state" using (arrangement.equals(allContracts))
|
||||
}
|
||||
|
||||
}
|
||||
@ -239,17 +239,17 @@ class UniversalContract : Contract {
|
||||
is Commands.Issue -> {
|
||||
val outState = tx.outputs.single() as State
|
||||
requireThat {
|
||||
"the transaction is signed by all liable parties" by (liableParties(outState.details).all { it in cmd.signers })
|
||||
"the transaction has no input states" by tx.inputs.isEmpty()
|
||||
"the transaction is signed by all liable parties" using (liableParties(outState.details).all { it in cmd.signers })
|
||||
"the transaction has no input states" using tx.inputs.isEmpty()
|
||||
}
|
||||
}
|
||||
is Commands.Move -> {
|
||||
val inState = tx.inputs.single() as State
|
||||
val outState = tx.outputs.single() as State
|
||||
requireThat {
|
||||
"the transaction is signed by all liable parties" by
|
||||
"the transaction is signed by all liable parties" using
|
||||
(liableParties(outState.details).all { it in cmd.signers })
|
||||
"output state does not reflect move command" by
|
||||
"output state does not reflect move command" using
|
||||
(replaceParty(inState.details, value.from, value.to).equals(outState.details))
|
||||
}
|
||||
}
|
||||
@ -267,8 +267,8 @@ class UniversalContract : Contract {
|
||||
value.fixes.associateBy({ it.of }, { it.value }), unusedFixes)
|
||||
|
||||
requireThat {
|
||||
"relevant fixing must be included" by unusedFixes.isEmpty()
|
||||
"output state does not reflect fix command" by
|
||||
"relevant fixing must be included" using unusedFixes.isEmpty()
|
||||
"output state does not reflect fix command" using
|
||||
(expectedArr.equals(outState.details))
|
||||
}
|
||||
}
|
||||
|
@ -208,12 +208,12 @@ public class JavaCommercialPaper implements Contract {
|
||||
Amount<Issued<Currency>> received = CashKt.sumCashBy(tx.getOutputs(), input.getOwner());
|
||||
|
||||
requireThat(require -> {
|
||||
require.by("must be timestamped", timestamp != null);
|
||||
require.by("received amount equals the face value: "
|
||||
require.using("must be timestamped", timestamp != null);
|
||||
require.using("received amount equals the face value: "
|
||||
+ received + " vs " + input.getFaceValue(), received.equals(input.getFaceValue()));
|
||||
require.by("the paper must have matured", time != null && !time.isBefore(input.getMaturityDate()));
|
||||
require.by("the received amount equals the face value", input.getFaceValue().equals(received));
|
||||
require.by("the paper must be destroyed", outputs.isEmpty());
|
||||
require.using("the paper must have matured", time != null && !time.isBefore(input.getMaturityDate()));
|
||||
require.using("the received amount equals the face value", input.getFaceValue().equals(received));
|
||||
require.using("the paper must be destroyed", outputs.isEmpty());
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
@ -244,11 +244,11 @@ public class JavaCommercialPaper implements Contract {
|
||||
: timestampCommand.getBefore();
|
||||
|
||||
requireThat(require -> {
|
||||
require.by("output values sum to more than the inputs", inputs.isEmpty());
|
||||
require.by("output values sum to more than the inputs", output.faceValue.getQuantity() > 0);
|
||||
require.by("must be timestamped", timestampCommand != null);
|
||||
require.by("the maturity date is not in the past", time != null && time.isBefore(output.getMaturityDate()));
|
||||
require.by("output states are issued by a command signer", cmd.getSigners().contains(output.issuance.getParty().getOwningKey()));
|
||||
require.using("output values sum to more than the inputs", inputs.isEmpty());
|
||||
require.using("output values sum to more than the inputs", output.faceValue.getQuantity() > 0);
|
||||
require.using("must be timestamped", timestampCommand != null);
|
||||
require.using("the maturity date is not in the past", time != null && time.isBefore(output.getMaturityDate()));
|
||||
require.using("output states are issued by a command signer", cmd.getSigners().contains(output.issuance.getParty().getOwningKey()));
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
|
||||
|
@ -143,8 +143,8 @@ class CommercialPaper : Contract {
|
||||
val command = commands.requireSingleCommand<Commands.Move>()
|
||||
val input = inputs.single()
|
||||
requireThat {
|
||||
"the transaction is signed by the owner of the CP" by (input.owner in command.signers)
|
||||
"the state is propagated" by (outputs.size == 1)
|
||||
"the transaction is signed by the owner of the CP" using (input.owner in command.signers)
|
||||
"the state is propagated" using (outputs.size == 1)
|
||||
// Don't need to check anything else, as if outputs.size == 1 then the output is equal to
|
||||
// the input ignoring the owner field due to the grouping.
|
||||
}
|
||||
@ -169,10 +169,10 @@ class CommercialPaper : Contract {
|
||||
val received = tx.outputs.sumCashBy(input.owner)
|
||||
val time = timestamp?.after ?: throw IllegalArgumentException("Redemptions must be timestamped")
|
||||
requireThat {
|
||||
"the paper must have matured" by (time >= input.maturityDate)
|
||||
"the received amount equals the face value" by (received == input.faceValue)
|
||||
"the paper must be destroyed" by outputs.isEmpty()
|
||||
"the transaction is signed by the owner of the CP" by (input.owner in command.signers)
|
||||
"the paper must have matured" using (time >= input.maturityDate)
|
||||
"the received amount equals the face value" using (received == input.faceValue)
|
||||
"the paper must be destroyed" using outputs.isEmpty()
|
||||
"the transaction is signed by the owner of the CP" using (input.owner in command.signers)
|
||||
}
|
||||
|
||||
return setOf(command.value)
|
||||
|
@ -69,8 +69,8 @@ class CommercialPaperLegacy : Contract {
|
||||
is Commands.Move -> {
|
||||
val input = inputs.single()
|
||||
requireThat {
|
||||
"the transaction is signed by the owner of the CP" by (input.owner in command.signers)
|
||||
"the state is propagated" by (outputs.size == 1)
|
||||
"the transaction is signed by the owner of the CP" using (input.owner in command.signers)
|
||||
"the state is propagated" using (outputs.size == 1)
|
||||
// Don't need to check anything else, as if outputs.size == 1 then the output is equal to
|
||||
// the input ignoring the owner field due to the grouping.
|
||||
}
|
||||
@ -82,10 +82,10 @@ class CommercialPaperLegacy : Contract {
|
||||
val received = tx.outputs.sumCashBy(input.owner)
|
||||
val time = timestamp?.after ?: throw IllegalArgumentException("Redemptions must be timestamped")
|
||||
requireThat {
|
||||
"the paper must have matured" by (time >= input.maturityDate)
|
||||
"the received amount equals the face value" by (received == input.faceValue)
|
||||
"the paper must be destroyed" by outputs.isEmpty()
|
||||
"the transaction is signed by the owner of the CP" by (input.owner in command.signers)
|
||||
"the paper must have matured" using (time >= input.maturityDate)
|
||||
"the received amount equals the face value" using (received == input.faceValue)
|
||||
"the paper must be destroyed" using outputs.isEmpty()
|
||||
"the transaction is signed by the owner of the CP" using (input.owner in command.signers)
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,14 +94,14 @@ class CommercialPaperLegacy : Contract {
|
||||
val time = timestamp?.before ?: throw IllegalArgumentException("Issuances must be timestamped")
|
||||
requireThat {
|
||||
// Don't allow people to issue commercial paper under other entities identities.
|
||||
"output states are issued by a command signer" by
|
||||
"output states are issued by a command signer" using
|
||||
(output.issuance.party.owningKey in command.signers)
|
||||
"output values sum to more than the inputs" by (output.faceValue.quantity > 0)
|
||||
"the maturity date is not in the past" by (time < output.maturityDate)
|
||||
"output values sum to more than the inputs" using (output.faceValue.quantity > 0)
|
||||
"the maturity date is not in the past" using (time < output.maturityDate)
|
||||
// Don't allow an existing CP state to be replaced by this issuance.
|
||||
// TODO: this has a weird/incorrect assertion string because it doesn't quite match the logic in the clause version.
|
||||
// TODO: Consider how to handle the case of mistaken issuances, or other need to patch.
|
||||
"output values sum to more than the inputs" by inputs.isEmpty()
|
||||
"output values sum to more than the inputs" using inputs.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,8 +160,8 @@ class Obligation<P : Any> : Contract {
|
||||
.filter { it.amount.token in template.acceptableIssuedProducts }
|
||||
// Catch that there's nothing useful here, so we can dump out a useful error
|
||||
requireThat {
|
||||
"there are fungible asset state outputs" by (assetStates.size > 0)
|
||||
"there are defined acceptable fungible asset states" by (acceptableAssetStates.size > 0)
|
||||
"there are fungible asset state outputs" using (assetStates.size > 0)
|
||||
"there are defined acceptable fungible asset states" using (acceptableAssetStates.size > 0)
|
||||
}
|
||||
|
||||
val amountReceivedByOwner = acceptableAssetStates.groupBy { it.owner }
|
||||
@ -184,15 +184,15 @@ class Obligation<P : Any> : Contract {
|
||||
requireThat {
|
||||
// Insist that we can be the only contract consuming inputs, to ensure no other contract can think it's being
|
||||
// settled as well
|
||||
"all move commands relate to this contract" by (moveCommands.map { it.value.contractHash }
|
||||
"all move commands relate to this contract" using (moveCommands.map { it.value.contractHash }
|
||||
.all { it == null || it == Obligation<P>().legalContractReference })
|
||||
// Settle commands exclude all other commands, so we don't need to check for contracts moving at the same
|
||||
// time.
|
||||
"amounts paid must match recipients to settle" by inputs.map { it.owner }.containsAll(amountReceivedByOwner.keys)
|
||||
"amount in settle command ${command.value.amount} matches settled total $totalAmountSettled" by (command.value.amount == totalAmountSettled)
|
||||
"signatures are present from all obligors" by command.signers.containsAll(requiredSigners)
|
||||
"there are no zero sized inputs" by inputs.none { it.amount.quantity == 0L }
|
||||
"at obligor ${obligor} the obligations after settlement balance" by
|
||||
"amounts paid must match recipients to settle" using inputs.map { it.owner }.containsAll(amountReceivedByOwner.keys)
|
||||
"amount in settle command ${command.value.amount} matches settled total $totalAmountSettled" using (command.value.amount == totalAmountSettled)
|
||||
"signatures are present from all obligors" using command.signers.containsAll(requiredSigners)
|
||||
"there are no zero sized inputs" using inputs.none { it.amount.quantity == 0L }
|
||||
"at obligor ${obligor} the obligations after settlement balance" using
|
||||
(inputAmount == outputAmount + Amount(totalPenniesSettled, groupingKey))
|
||||
}
|
||||
return setOf(command.value)
|
||||
@ -216,8 +216,8 @@ class Obligation<P : Any> : Contract {
|
||||
private fun verify(inputs: List<State<P>>,
|
||||
outputs: List<State<P>>): Set<C> {
|
||||
requireThat {
|
||||
"all inputs are in the normal state " by inputs.all { it.lifecycle == Lifecycle.NORMAL }
|
||||
"all outputs are in the normal state " by outputs.all { it.lifecycle == Lifecycle.NORMAL }
|
||||
"all inputs are in the normal state " using inputs.all { it.lifecycle == Lifecycle.NORMAL }
|
||||
"all outputs are in the normal state " using outputs.all { it.lifecycle == Lifecycle.NORMAL }
|
||||
}
|
||||
return emptySet()
|
||||
}
|
||||
@ -407,17 +407,17 @@ class Obligation<P : Any> : Contract {
|
||||
val expectedOutput = input.copy(lifecycle = expectedOutputLifecycle)
|
||||
|
||||
requireThat {
|
||||
"there is a timestamp from the authority" by (timestamp != null)
|
||||
"the due date has passed" by (timestamp!!.after?.isAfter(deadline) ?: false)
|
||||
"input state lifecycle is correct" by (input.lifecycle == expectedInputLifecycle)
|
||||
"output state corresponds exactly to input state, with lifecycle changed" by (expectedOutput == actualOutput)
|
||||
"there is a timestamp from the authority" using (timestamp != null)
|
||||
"the due date has passed" using (timestamp!!.after?.isAfter(deadline) ?: false)
|
||||
"input state lifecycle is correct" using (input.lifecycle == expectedInputLifecycle)
|
||||
"output state corresponds exactly to input state, with lifecycle changed" using (expectedOutput == actualOutput)
|
||||
}
|
||||
}
|
||||
}
|
||||
val owningPubKeys = inputs.filter { it is State<P> }.map { (it as State<P>).beneficiary }.toSet()
|
||||
val keysThatSigned = setLifecycleCommand.signers.toSet()
|
||||
requireThat {
|
||||
"the owning keys are a subset of the signing keys" by keysThatSigned.containsAll(owningPubKeys)
|
||||
"the owning keys are a subset of the signing keys" using keysThatSigned.containsAll(owningPubKeys)
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,10 +434,10 @@ class Obligation<P : Any> : Contract {
|
||||
val netState = states.firstOrNull()?.bilateralNetState
|
||||
|
||||
requireThat {
|
||||
"at least two states are provided" by (states.size >= 2)
|
||||
"all states are in the normal lifecycle state " by (states.all { it.lifecycle == Lifecycle.NORMAL })
|
||||
"all states must be bilateral nettable" by (states.all { it.bilateralNetState == netState })
|
||||
"signer is in the state parties" by (signer in netState!!.partyKeys)
|
||||
"at least two states are provided" using (states.size >= 2)
|
||||
"all states are in the normal lifecycle state " using (states.all { it.lifecycle == Lifecycle.NORMAL })
|
||||
"all states must be bilateral nettable" using (states.all { it.bilateralNetState == netState })
|
||||
"signer is in the state parties" using (signer in netState!!.partyKeys)
|
||||
}
|
||||
|
||||
val out = states.reduce(State<P>::net)
|
||||
@ -484,7 +484,7 @@ class Obligation<P : Any> : Contract {
|
||||
notary: Party,
|
||||
vararg states: State<P>) {
|
||||
requireThat {
|
||||
"all states are in the normal lifecycle state " by (states.all { it.lifecycle == Lifecycle.NORMAL })
|
||||
"all states are in the normal lifecycle state " using (states.all { it.lifecycle == Lifecycle.NORMAL })
|
||||
}
|
||||
val groups = states.groupBy { it.multilateralNetState }
|
||||
val partyLookup = HashMap<PublicKey, AnonymousParty>()
|
||||
@ -563,11 +563,11 @@ class Obligation<P : Any> : Contract {
|
||||
val obligationOwner = states.first().data.beneficiary
|
||||
|
||||
requireThat {
|
||||
"all fungible asset states use the same notary" by (assetStatesAndRefs.all { it.state.notary == notary })
|
||||
"all obligation states are in the normal state" by (statesAndRefs.all { it.state.data.lifecycle == Lifecycle.NORMAL })
|
||||
"all obligation states use the same notary" by (statesAndRefs.all { it.state.notary == notary })
|
||||
"all obligation states have the same obligor" by (statesAndRefs.all { it.state.data.obligor == obligationIssuer })
|
||||
"all obligation states have the same beneficiary" by (statesAndRefs.all { it.state.data.beneficiary == obligationOwner })
|
||||
"all fungible asset states use the same notary" using (assetStatesAndRefs.all { it.state.notary == notary })
|
||||
"all obligation states are in the normal state" using (statesAndRefs.all { it.state.data.lifecycle == Lifecycle.NORMAL })
|
||||
"all obligation states use the same notary" using (statesAndRefs.all { it.state.notary == notary })
|
||||
"all obligation states have the same obligor" using (statesAndRefs.all { it.state.data.obligor == obligationIssuer })
|
||||
"all obligation states have the same beneficiary" using (statesAndRefs.all { it.state.data.beneficiary == obligationOwner })
|
||||
}
|
||||
|
||||
// TODO: A much better (but more complex) solution would be to have two iterators, one for obligations,
|
||||
|
@ -109,8 +109,8 @@ abstract class AbstractConserveAmount<S : FungibleAsset<T>, C : CommandData, T :
|
||||
val amountExitingLedger: Amount<Issued<T>> = exitCommand?.value?.amount ?: Amount(0, groupingKey)
|
||||
|
||||
requireThat {
|
||||
"there are no zero sized inputs" by inputs.none { it.amount.quantity == 0L }
|
||||
"for reference ${deposit.reference} at issuer ${deposit.party} the amounts balance: ${inputAmount.quantity} - ${amountExitingLedger.quantity} != ${outputAmount.quantity}" by
|
||||
"there are no zero sized inputs" using inputs.none { it.amount.quantity == 0L }
|
||||
"for reference ${deposit.reference} at issuer ${deposit.party} the amounts balance: ${inputAmount.quantity} - ${amountExitingLedger.quantity} != ${outputAmount.quantity}" using
|
||||
(inputAmount == outputAmount + amountExitingLedger)
|
||||
}
|
||||
|
||||
|
@ -41,11 +41,11 @@ abstract class AbstractIssue<in S : ContractState, C : CommandData, T : Any>(
|
||||
val inputAmount = inputs.sumOrZero(groupingKey)
|
||||
val outputAmount = outputs.sum()
|
||||
requireThat {
|
||||
"the issue command has a nonce" by (issueCommand.value.nonce != 0L)
|
||||
"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 in issueCommand.signingParties)
|
||||
"output states are issued by a command signer" by (issuer.owningKey in issueCommand.signers)
|
||||
"output values sum to more than the inputs" by (outputAmount > inputAmount)
|
||||
"output states are issued by a command signer" using (issuer.owningKey in issueCommand.signers)
|
||||
"output values sum to more than the inputs" using (outputAmount > inputAmount)
|
||||
}
|
||||
|
||||
// This is safe because we've taken the command from a collection of C objects at the start
|
||||
|
@ -79,9 +79,10 @@ open class NetClause<C : CommandData, P : Any> : Clause<ContractState, C, Unit>(
|
||||
// Sum the columns of the matrices. This will yield the net amount payable to/from each party to/from all other participants.
|
||||
// The two summaries must match, reflecting that the amounts owed match on both input and output.
|
||||
requireThat {
|
||||
"all input states use the same template" by (inputs.all { it.template == template })
|
||||
"all output states use the same template" by (outputs.all { it.template == template })
|
||||
"amounts owed on input and output must match" by (sumAmountsDue(inputBalances) == sumAmountsDue(outputBalances))
|
||||
"all input states use the same template" using (inputs.all { it.template == template })
|
||||
"all output states use the same template" using (outputs.all { it.template == template })
|
||||
"amounts owed on input and output must match" using (sumAmountsDue(inputBalances) == sumAmountsDue
|
||||
(outputBalances))
|
||||
}
|
||||
|
||||
// TODO: Handle proxies nominated by parties, i.e. a central clearing service
|
||||
|
@ -14,7 +14,7 @@ open class NoZeroSizedOutputs<in S : FungibleAsset<T>, C : CommandData, T : Any>
|
||||
commands: List<AuthenticatedObject<C>>,
|
||||
groupingKey: Issued<T>?): Set<C> {
|
||||
requireThat {
|
||||
"there are no zero sized outputs" by outputs.none { it.amount.quantity == 0L }
|
||||
"there are no zero sized outputs" using outputs.none { it.amount.quantity == 0L }
|
||||
}
|
||||
return emptySet()
|
||||
}
|
||||
|
@ -479,22 +479,22 @@ class InterestRateSwap : Contract {
|
||||
// These functions may make more sense to use for basket types, but for now let's leave them here
|
||||
fun checkLegDates(legs: List<CommonLeg>) {
|
||||
requireThat {
|
||||
"Effective date is before termination date" by legs.all { it.effectiveDate < it.terminationDate }
|
||||
"Effective dates are in alignment" by legs.all { it.effectiveDate == legs[0].effectiveDate }
|
||||
"Termination dates are in alignment" by legs.all { it.terminationDate == legs[0].terminationDate }
|
||||
"Effective date is before termination date" using legs.all { it.effectiveDate < it.terminationDate }
|
||||
"Effective dates are in alignment" using legs.all { it.effectiveDate == legs[0].effectiveDate }
|
||||
"Termination dates are in alignment" using legs.all { it.terminationDate == legs[0].terminationDate }
|
||||
}
|
||||
}
|
||||
|
||||
fun checkLegAmounts(legs: List<CommonLeg>) {
|
||||
requireThat {
|
||||
"The notional is non zero" by legs.any { it.notional.quantity > (0).toLong() }
|
||||
"The notional for all legs must be the same" by legs.all { it.notional == legs[0].notional }
|
||||
"The notional is non zero" using legs.any { it.notional.quantity > (0).toLong() }
|
||||
"The notional for all legs must be the same" using legs.all { it.notional == legs[0].notional }
|
||||
}
|
||||
for (leg: CommonLeg in legs) {
|
||||
if (leg is FixedLeg<*>) {
|
||||
requireThat {
|
||||
// TODO: Confirm: would someone really enter a swap with a negative fixed rate?
|
||||
"Fixed leg rate must be positive" by leg.fixedRate.isPositive()
|
||||
"Fixed leg rate must be positive" using leg.fixedRate.isPositive()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -547,21 +547,21 @@ class InterestRateSwap : Contract {
|
||||
val command = tx.commands.requireSingleCommand<Commands.Agree>()
|
||||
val irs = outputs.filterIsInstance<State<*>>().single()
|
||||
requireThat {
|
||||
"There are no in states for an agreement" by inputs.isEmpty()
|
||||
"There are events in the fix schedule" by (irs.calculation.fixedLegPaymentSchedule.isNotEmpty())
|
||||
"There are events in the float schedule" by (irs.calculation.floatingLegPaymentSchedule.isNotEmpty())
|
||||
"All notionals must be non zero" by (irs.fixedLeg.notional.quantity > 0 && irs.floatingLeg.notional.quantity > 0)
|
||||
"The fixed leg rate must be positive" by (irs.fixedLeg.fixedRate.isPositive())
|
||||
"The currency of the notionals must be the same" by (irs.fixedLeg.notional.token == irs.floatingLeg.notional.token)
|
||||
"All leg notionals must be the same" by (irs.fixedLeg.notional == irs.floatingLeg.notional)
|
||||
"There are no in states for an agreement" using inputs.isEmpty()
|
||||
"There are events in the fix schedule" using (irs.calculation.fixedLegPaymentSchedule.isNotEmpty())
|
||||
"There are events in the float schedule" using (irs.calculation.floatingLegPaymentSchedule.isNotEmpty())
|
||||
"All notionals must be non zero" using (irs.fixedLeg.notional.quantity > 0 && irs.floatingLeg.notional.quantity > 0)
|
||||
"The fixed leg rate must be positive" using (irs.fixedLeg.fixedRate.isPositive())
|
||||
"The currency of the notionals must be the same" using (irs.fixedLeg.notional.token == irs.floatingLeg.notional.token)
|
||||
"All leg notionals must be the same" using (irs.fixedLeg.notional == irs.floatingLeg.notional)
|
||||
|
||||
"The effective date is before the termination date for the fixed leg" by (irs.fixedLeg.effectiveDate < irs.fixedLeg.terminationDate)
|
||||
"The effective date is before the termination date for the floating leg" by (irs.floatingLeg.effectiveDate < irs.floatingLeg.terminationDate)
|
||||
"The effective dates are aligned" by (irs.floatingLeg.effectiveDate == irs.fixedLeg.effectiveDate)
|
||||
"The termination dates are aligned" by (irs.floatingLeg.terminationDate == irs.fixedLeg.terminationDate)
|
||||
"The rates are valid" by checkRates(listOf(irs.fixedLeg, irs.floatingLeg))
|
||||
"The schedules are valid" by checkSchedules(listOf(irs.fixedLeg, irs.floatingLeg))
|
||||
"The fixing period date offset cannot be negative" by (irs.floatingLeg.fixingPeriodOffset >= 0)
|
||||
"The effective date is before the termination date for the fixed leg" using (irs.fixedLeg.effectiveDate < irs.fixedLeg.terminationDate)
|
||||
"The effective date is before the termination date for the floating leg" using (irs.floatingLeg.effectiveDate < irs.floatingLeg.terminationDate)
|
||||
"The effective dates are aligned" using (irs.floatingLeg.effectiveDate == irs.fixedLeg.effectiveDate)
|
||||
"The termination dates are aligned" using (irs.floatingLeg.terminationDate == irs.fixedLeg.terminationDate)
|
||||
"The rates are valid" using checkRates(listOf(irs.fixedLeg, irs.floatingLeg))
|
||||
"The schedules are valid" using checkSchedules(listOf(irs.fixedLeg, irs.floatingLeg))
|
||||
"The fixing period date offset cannot be negative" using (irs.floatingLeg.fixingPeriodOffset >= 0)
|
||||
|
||||
// TODO: further tests
|
||||
}
|
||||
@ -588,8 +588,8 @@ class InterestRateSwap : Contract {
|
||||
// Having both of these tests are "redundant" as far as verify() goes, however, by performing both
|
||||
// we can relay more information back to the user in the case of failure.
|
||||
requireThat {
|
||||
"There is at least one difference in the IRS floating leg payment schedules" by !paymentDifferences.isEmpty()
|
||||
"There is only one change in the IRS floating leg payment schedule" by (paymentDifferences.size == 1)
|
||||
"There is at least one difference in the IRS floating leg payment schedules" using !paymentDifferences.isEmpty()
|
||||
"There is only one change in the IRS floating leg payment schedule" using (paymentDifferences.size == 1)
|
||||
}
|
||||
|
||||
val changedRates = paymentDifferences.single().second // Ignore the date of the changed rate (we checked that earlier).
|
||||
@ -597,19 +597,19 @@ class InterestRateSwap : Contract {
|
||||
val fixValue = command.value.fix
|
||||
// Need to check that everything is the same apart from the new fixed rate entry.
|
||||
requireThat {
|
||||
"The fixed leg parties are constant" by (irs.fixedLeg.fixedRatePayer == prevIrs.fixedLeg.fixedRatePayer) // Although superseded by the below test, this is included for a regression issue
|
||||
"The fixed leg is constant" by (irs.fixedLeg == prevIrs.fixedLeg)
|
||||
"The floating leg is constant" by (irs.floatingLeg == prevIrs.floatingLeg)
|
||||
"The common values are constant" by (irs.common == prevIrs.common)
|
||||
"The fixed leg payment schedule is constant" by (irs.calculation.fixedLegPaymentSchedule == prevIrs.calculation.fixedLegPaymentSchedule)
|
||||
"The expression is unchanged" by (irs.calculation.expression == prevIrs.calculation.expression)
|
||||
"There is only one changed payment in the floating leg" by (paymentDifferences.size == 1)
|
||||
"There changed payment is a floating payment" by (oldFloatingRatePaymentEvent.rate is ReferenceRate)
|
||||
"The new payment is a fixed payment" by (newFixedRatePaymentEvent.rate is FixedRate)
|
||||
"The changed payments dates are aligned" by (oldFloatingRatePaymentEvent.date == newFixedRatePaymentEvent.date)
|
||||
"The new payment has the correct rate" by (newFixedRatePaymentEvent.rate.ratioUnit!!.value == fixValue.value)
|
||||
"The fixing is for the next required date" by (prevIrs.calculation.nextFixingDate() == fixValue.of.forDay)
|
||||
"The fix payment has the same currency as the notional" by (newFixedRatePaymentEvent.flow.token == irs.floatingLeg.notional.token)
|
||||
"The fixed leg parties are constant" using (irs.fixedLeg.fixedRatePayer == prevIrs.fixedLeg.fixedRatePayer) // Although superseded by the below test, this is included for a regression issue
|
||||
"The fixed leg is constant" using (irs.fixedLeg == prevIrs.fixedLeg)
|
||||
"The floating leg is constant" using (irs.floatingLeg == prevIrs.floatingLeg)
|
||||
"The common values are constant" using (irs.common == prevIrs.common)
|
||||
"The fixed leg payment schedule is constant" using (irs.calculation.fixedLegPaymentSchedule == prevIrs.calculation.fixedLegPaymentSchedule)
|
||||
"The expression is unchanged" using (irs.calculation.expression == prevIrs.calculation.expression)
|
||||
"There is only one changed payment in the floating leg" using (paymentDifferences.size == 1)
|
||||
"There changed payment is a floating payment" using (oldFloatingRatePaymentEvent.rate is ReferenceRate)
|
||||
"The new payment is a fixed payment" using (newFixedRatePaymentEvent.rate is FixedRate)
|
||||
"The changed payments dates are aligned" using (oldFloatingRatePaymentEvent.date == newFixedRatePaymentEvent.date)
|
||||
"The new payment has the correct rate" using (newFixedRatePaymentEvent.rate.ratioUnit!!.value == fixValue.value)
|
||||
"The fixing is for the next required date" using (prevIrs.calculation.nextFixingDate() == fixValue.of.forDay)
|
||||
"The fix payment has the same currency as the notional" using (newFixedRatePaymentEvent.flow.token == irs.floatingLeg.notional.token)
|
||||
// "The fixing is not in the future " by (fixCommand) // The oracle should not have signed this .
|
||||
}
|
||||
|
||||
@ -627,7 +627,7 @@ class InterestRateSwap : Contract {
|
||||
groupingKey: UniqueIdentifier?): Set<Commands> {
|
||||
val command = tx.commands.requireSingleCommand<Commands.Pay>()
|
||||
requireThat {
|
||||
"Payments not supported / verifiable yet" by false
|
||||
"Payments not supported / verifiable yet" using false
|
||||
}
|
||||
return setOf(command.value)
|
||||
}
|
||||
@ -644,8 +644,8 @@ class InterestRateSwap : Contract {
|
||||
val command = tx.commands.requireSingleCommand<Commands.Mature>()
|
||||
val irs = inputs.filterIsInstance<State<*>>().single()
|
||||
requireThat {
|
||||
"No more fixings to be applied" by (irs.calculation.nextFixingDate() == null)
|
||||
"The irs is fully consumed and there is no id matched output state" by outputs.isEmpty()
|
||||
"No more fixings to be applied" using (irs.calculation.nextFixingDate() == null)
|
||||
"The irs is fully consumed and there is no id matched output state" using outputs.isEmpty()
|
||||
}
|
||||
|
||||
return setOf(command.value)
|
||||
|
@ -47,10 +47,10 @@ data class PortfolioSwap(override val legalContractReference: SecureHash = Secur
|
||||
val command = tx.commands.requireSingleCommand<Commands.Update>()
|
||||
|
||||
requireThat {
|
||||
"there is only one input" by (inputs.size == 1)
|
||||
"there is only one output" by (outputs.size == 1)
|
||||
"the valuer hasn't changed" by (inputs[0].valuer == outputs[0].valuer)
|
||||
"the linear id hasn't changed" by (inputs[0].linearId == outputs[0].linearId)
|
||||
"there is only one input" using (inputs.size == 1)
|
||||
"there is only one output" using (outputs.size == 1)
|
||||
"the valuer hasn't changed" using (inputs[0].valuer == outputs[0].valuer)
|
||||
"the linear id hasn't changed" using (inputs[0].linearId == outputs[0].linearId)
|
||||
}
|
||||
|
||||
return setOf(command.value)
|
||||
@ -68,10 +68,10 @@ data class PortfolioSwap(override val legalContractReference: SecureHash = Secur
|
||||
val command = tx.commands.requireSingleCommand<Commands.Agree>()
|
||||
|
||||
requireThat {
|
||||
"there are no inputs" by (inputs.size == 0)
|
||||
"there is one output" by (outputs.size == 1)
|
||||
"valuer must be a party" by (outputs[0].parties.contains(outputs[0].valuer))
|
||||
"all participants must be parties" by (outputs[0].parties.map { it.owningKey }.containsAll(outputs[0].participants))
|
||||
"there are no inputs" using (inputs.size == 0)
|
||||
"there is one output" using (outputs.size == 1)
|
||||
"valuer must be a party" using (outputs[0].parties.contains(outputs[0].valuer))
|
||||
"all participants must be parties" using (outputs[0].parties.map { it.owningKey }.containsAll(outputs[0].participants))
|
||||
}
|
||||
|
||||
return setOf(command.value)
|
||||
|
Loading…
Reference in New Issue
Block a user