Replace 'by' with 'using' to avoid overloading Kotlin keyword in contracts DSL. Deprecates 'by' with offered replacement.

This commit is contained in:
gary-rowe 2017-04-04 21:41:50 +01:00 committed by Mike Hearn
parent 36d5d0d7b2
commit 108f171e03
16 changed files with 149 additions and 141 deletions

View File

@ -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
}

View File

@ -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()
}

View File

@ -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())
}

View File

@ -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)
}
}

View File

@ -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))
}
}
}

View File

@ -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))
}
}

View File

@ -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;
});

View File

@ -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)

View File

@ -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()
}
}

View File

@ -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,

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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()
}

View File

@ -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)

View File

@ -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)