diff --git a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java index c70d06bdd0..c052e5f987 100644 --- a/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java +++ b/contracts/src/main/java/com/r3corda/contracts/JavaCommercialPaper.java @@ -3,8 +3,10 @@ package com.r3corda.contracts; import com.google.common.collect.*; import com.r3corda.contracts.asset.*; import com.r3corda.core.contracts.*; +import static com.r3corda.core.contracts.ContractsDSL.requireThat; import com.r3corda.core.contracts.TransactionForContract.*; import com.r3corda.core.crypto.*; +import kotlin.Unit; import org.jetbrains.annotations.*; import java.security.*; @@ -171,59 +173,52 @@ public class JavaCommercialPaper implements Contract { if (cmd.getValue() instanceof JavaCommercialPaper.Commands.Issue) { Commands.Issue issueCommand = (Commands.Issue) cmd.getValue(); State output = single(outputs); - if (!inputs.isEmpty()) { - throw new IllegalStateException("Failed Requirement: output values sum to more than the inputs"); - } - if (output.faceValue.getQuantity() == 0) { - throw new IllegalStateException("Failed Requirement: output values sum to more than the inputs"); - } - TimestampCommand timestampCommand = tx.getTimestampBy(issueCommand.notary); - if (timestampCommand == null) - throw new IllegalArgumentException("Failed Requirement: must be timestamped"); + Instant time = null == timestampCommand + ? null + : timestampCommand.getBefore(); - Instant time = timestampCommand.getBefore(); - - if (time == null || !time.isBefore(output.maturityDate)) { - throw new IllegalStateException("Failed Requirement: the maturity date is not in the past"); - } - - if (!cmd.getSigners().contains(output.issuance.getParty().getOwningKey())) { - throw new IllegalStateException("Failed Requirement: output states are issued by a command signer"); - } + 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())); + return Unit.INSTANCE; + }); } else { // Everything else (Move, Redeem) requires inputs (they are not first to be actioned) // There should be only a single input due to aggregation above State input = single(inputs); - if (!cmd.getSigners().contains(input.getOwner())) - throw new IllegalStateException("Failed requirement: the transaction is signed by the owner of the CP"); + requireThat(require -> { + require.by("the transaction is signed by the owner of the CP", cmd.getSigners().contains(input.getOwner())); + return Unit.INSTANCE; + }); if (cmd.getValue() instanceof JavaCommercialPaper.Commands.Move) { - // Check the output CP state is the same as the input state, ignoring the owner field. - State output = single(outputs); - - if (!output.getFaceValue().equals(input.getFaceValue()) || - !output.getIssuance().equals(input.getIssuance()) || - !output.getMaturityDate().equals(input.getMaturityDate())) - throw new IllegalStateException("Failed requirement: the output state is the same as the input state except for owner"); + requireThat(require -> { + require.by("the state is propagated", outputs.size() == 1); + return Unit.INSTANCE; + }); + // 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. } else if (cmd.getValue() instanceof JavaCommercialPaper.Commands.Redeem) { TimestampCommand timestampCommand = tx.getTimestampBy(((Commands.Redeem) cmd.getValue()).notary); - if (timestampCommand == null) - throw new IllegalArgumentException("Failed Requirement: must be timestamped"); - Instant time = timestampCommand.getBefore(); - + Instant time = null == timestampCommand + ? null + : timestampCommand.getBefore(); Amount> received = CashKt.sumCashBy(tx.getOutputs(), input.getOwner()); - if (!received.equals(input.getFaceValue())) - throw new IllegalStateException("Failed Requirement: received amount equals the face value: " - + received + " vs " + input.getFaceValue()); - if (time == null || time.isBefore(input.getMaturityDate())) - throw new IllegalStateException("Failed requirement: the paper must have matured"); - if (!input.getFaceValue().equals(received)) - throw new IllegalStateException("Failed requirement: the received amount equals the face value"); - if (!outputs.isEmpty()) - throw new IllegalStateException("Failed requirement: the paper must be destroyed"); + requireThat(require -> { + require.by("must be timestamped", timestampCommand != null); + require.by("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()); + return Unit.INSTANCE; + }); } } } diff --git a/docs/source/tutorial-contract.rst b/docs/source/tutorial-contract.rst index cee7487eeb..6ff025760c 100644 --- a/docs/source/tutorial-contract.rst +++ b/docs/source/tutorial-contract.rst @@ -421,29 +421,34 @@ logic. // For now do not allow multiple pieces of CP to trade in a single transaction. Study this more! State input = single(filterIsInstance(inputs, State.class)); - if (!cmd.getSigners().contains(input.getOwner())) - throw new IllegalStateException("Failed requirement: the transaction is signed by the owner of the CP"); + requireThat(require -> { + require.by("the transaction is signed by the owner of the CP", cmd.getSigners().contains(input.getOwner())); + return Unit.INSTANCE; + }); if (cmd.getValue() instanceof JavaCommercialPaper.Commands.Move) { - // Check the output CP state is the same as the input state, ignoring the owner field. - State output = single(outputs); - - if (!output.getFaceValue().equals(input.getFaceValue()) || - !output.getIssuance().equals(input.getIssuance()) || - !output.getMaturityDate().equals(input.getMaturityDate())) - throw new IllegalStateException("Failed requirement: the output state is the same as the input state except for owner"); + requireThat(require -> { + require.by("the state is propagated", outputs.size() == 1); + return Unit.INSTANCE; + }); + // 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. } else if (cmd.getValue() instanceof JavaCommercialPaper.Commands.Redeem) { - Amount received = CashKt.sumCashOrNull(inputs); - if (time == null) - throw new IllegalArgumentException("Redemption transactions must be timestamped"); - if (received == null) - throw new IllegalStateException("Failed requirement: no cash being redeemed"); - if (input.getMaturityDate().isAfter(time)) - throw new IllegalStateException("Failed requirement: the paper must have matured"); - if (!input.getFaceValue().equals(received)) - throw new IllegalStateException("Failed requirement: the received amount equals the face value"); - if (!outputs.isEmpty()) - throw new IllegalStateException("Failed requirement: the paper must be destroyed"); + TimestampCommand timestampCommand = tx.getTimestampBy(((Commands.Redeem) cmd.getValue()).notary); + Instant time = null == timestampCommand + ? null + : timestampCommand.getBefore(); + Amount> received = CashKt.sumCashBy(tx.getOutputs(), input.getOwner()); + + requireThat(require -> { + require.by("must be timestamped", timestampCommand != null); + require.by("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()); + return Unit.INSTANCE; + }); } else if (cmd.getValue() instanceof JavaCommercialPaper.Commands.Issue) { // .. etc .. (see Kotlin for full definition) }