Minor: cleanup the commercial paper contracts.

There's no need for the notary to be specified in commands. A few other tweaks and additions found whilst refreshing the docsite.
This commit is contained in:
Mike Hearn 2016-08-23 22:04:45 +02:00
parent 74e5e1bce8
commit c8323099bb
6 changed files with 67 additions and 63 deletions

View File

@ -3,19 +3,17 @@ package com.r3corda.contracts;
import com.google.common.collect.*; import com.google.common.collect.*;
import com.r3corda.contracts.asset.*; import com.r3corda.contracts.asset.*;
import com.r3corda.core.contracts.*; import com.r3corda.core.contracts.*;
import static com.r3corda.core.contracts.ContractsDSL.requireThat;
import com.r3corda.core.contracts.Timestamp; import com.r3corda.core.contracts.Timestamp;
import com.r3corda.core.contracts.TransactionForContract.*; import com.r3corda.core.contracts.TransactionForContract.*;
import com.r3corda.core.contracts.clauses.*; import com.r3corda.core.contracts.clauses.*;
import com.r3corda.core.crypto.*; import com.r3corda.core.crypto.*;
import kotlin.Unit; import kotlin.*;
import org.jetbrains.annotations.*; import org.jetbrains.annotations.*;
import java.security.*; import java.security.*;
import java.time.*; import java.time.*;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.*;
import static com.r3corda.core.contracts.ContractsDSL.*; import static com.r3corda.core.contracts.ContractsDSL.*;
import static kotlin.collections.CollectionsKt.*; import static kotlin.collections.CollectionsKt.*;
@ -26,10 +24,9 @@ import static kotlin.collections.CollectionsKt.*;
* use of Kotlin for implementation of the framework does not impose the same language choice on contract developers. * use of Kotlin for implementation of the framework does not impose the same language choice on contract developers.
*/ */
public class JavaCommercialPaper implements Contract { public class JavaCommercialPaper implements Contract {
//public static SecureHash JCP_PROGRAM_ID = SecureHash.sha256("java commercial paper (this should be a bytecode hash)");
private static final Contract JCP_PROGRAM_ID = new JavaCommercialPaper(); private static final Contract JCP_PROGRAM_ID = new JavaCommercialPaper();
public static class State implements ContractState, ICommercialPaperState { public static class State implements OwnableState, ICommercialPaperState {
private PartyAndReference issuance; private PartyAndReference issuance;
private PublicKey owner; private PublicKey owner;
private Amount<Issued<Currency>> faceValue; private Amount<Issued<Currency>> faceValue;
@ -54,6 +51,12 @@ public class JavaCommercialPaper implements Contract {
return new State(this.issuance, newOwner, this.faceValue, this.maturityDate); return new State(this.issuance, newOwner, this.faceValue, this.maturityDate);
} }
@NotNull
@Override
public Pair<CommandData, OwnableState> withNewOwner(@NotNull PublicKey newOwner) {
return new Pair<>(new Commands.Move(), new State(this.issuance, newOwner, this.faceValue, this.maturityDate));
}
public ICommercialPaperState withIssuance(PartyAndReference newIssuance) { public ICommercialPaperState withIssuance(PartyAndReference newIssuance) {
return new State(newIssuance, this.owner, this.faceValue, this.maturityDate); return new State(newIssuance, this.owner, this.faceValue, this.maturityDate);
} }
@ -70,6 +73,7 @@ public class JavaCommercialPaper implements Contract {
return issuance; return issuance;
} }
@NotNull
public PublicKey getOwner() { public PublicKey getOwner() {
return owner; return owner;
} }
@ -86,7 +90,6 @@ public class JavaCommercialPaper implements Contract {
@Override @Override
public Contract getContract() { public Contract getContract() {
return JCP_PROGRAM_ID; return JCP_PROGRAM_ID;
//return SecureHash.sha256("java commercial paper (this should be a bytecode hash)");
} }
@Override @Override
@ -258,7 +261,6 @@ public class JavaCommercialPaper implements Contract {
@NotNull State token) { @NotNull State token) {
AuthenticatedObject<Commands.Issue> cmd = requireSingleCommand(tx.getCommands(), Commands.Issue.class); AuthenticatedObject<Commands.Issue> cmd = requireSingleCommand(tx.getCommands(), Commands.Issue.class);
State output = single(outputs); State output = single(outputs);
Party notary = cmd.getValue().notary;
Timestamp timestampCommand = tx.getTimestamp(); Timestamp timestampCommand = tx.getTimestamp();
Instant time = null == timestampCommand Instant time = null == timestampCommand
? null ? null
@ -285,35 +287,13 @@ public class JavaCommercialPaper implements Contract {
} }
class Redeem implements Commands { class Redeem implements Commands {
private final Party notary;
public Redeem(Party setNotary) {
this.notary = setNotary;
}
@Override @Override
public boolean equals(Object obj) { return obj instanceof Redeem; } public boolean equals(Object obj) { return obj instanceof Redeem; }
} }
class Issue implements Commands { class Issue implements Commands {
private final Party notary;
public Issue(Party setNotary) {
this.notary = setNotary;
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) { return obj instanceof Issue; }
if (obj instanceof Issue) {
Issue other = (Issue)obj;
return notary.equals(other.notary);
} else {
return false;
}
}
@Override
public int hashCode() { return notary.hashCode(); }
} }
} }
@ -340,13 +320,13 @@ public class JavaCommercialPaper implements Contract {
public TransactionBuilder generateIssue(@NotNull PartyAndReference issuance, @NotNull Amount<Issued<Currency>> faceValue, @Nullable Instant maturityDate, @NotNull Party notary) { public TransactionBuilder generateIssue(@NotNull PartyAndReference issuance, @NotNull Amount<Issued<Currency>> faceValue, @Nullable Instant maturityDate, @NotNull Party notary) {
State state = new State(issuance, issuance.getParty().getOwningKey(), faceValue, maturityDate); State state = new State(issuance, issuance.getParty().getOwningKey(), faceValue, maturityDate);
TransactionState output = new TransactionState<>(state, notary); TransactionState output = new TransactionState<>(state, notary);
return new TransactionType.General.Builder(notary).withItems(output, new Command(new Commands.Issue(notary), issuance.getParty().getOwningKey())); return new TransactionType.General.Builder(notary).withItems(output, new Command(new Commands.Issue(), issuance.getParty().getOwningKey()));
} }
public void generateRedeem(TransactionBuilder tx, StateAndRef<State> paper, List<StateAndRef<Cash.State>> wallet) throws InsufficientBalanceException { public void generateRedeem(TransactionBuilder tx, StateAndRef<State> paper, List<StateAndRef<Cash.State>> wallet) throws InsufficientBalanceException {
new Cash().generateSpend(tx, StructuresKt.withoutIssuer(paper.getState().getData().getFaceValue()), paper.getState().getData().getOwner(), wallet, null); new Cash().generateSpend(tx, StructuresKt.withoutIssuer(paper.getState().getData().getFaceValue()), paper.getState().getData().getOwner(), wallet, null);
tx.addInputState(paper); tx.addInputState(paper);
tx.addCommand(new Command(new Commands.Redeem(paper.getState().getNotary()), paper.getState().getData().getOwner())); tx.addCommand(new Command(new Commands.Redeem(), paper.getState().getData().getOwner()));
} }
public void generateMove(TransactionBuilder tx, StateAndRef<State> paper, PublicKey newOwner) { public void generateMove(TransactionBuilder tx, StateAndRef<State> paper, PublicKey newOwner) {

View File

@ -5,7 +5,10 @@ import com.r3corda.contracts.asset.InsufficientBalanceException
import com.r3corda.contracts.asset.sumCashBy import com.r3corda.contracts.asset.sumCashBy
import com.r3corda.contracts.clause.AbstractIssue import com.r3corda.contracts.clause.AbstractIssue
import com.r3corda.core.contracts.* import com.r3corda.core.contracts.*
import com.r3corda.core.contracts.clauses.* import com.r3corda.core.contracts.clauses.GroupClause
import com.r3corda.core.contracts.clauses.GroupClauseVerifier
import com.r3corda.core.contracts.clauses.MatchBehaviour
import com.r3corda.core.contracts.clauses.verifyClauses
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.crypto.toStringShort import com.r3corda.core.crypto.toStringShort
@ -108,7 +111,7 @@ class CommercialPaper : Contract {
commands: Collection<AuthenticatedObject<CommandData>>, commands: Collection<AuthenticatedObject<CommandData>>,
token: Issued<Terms>): Set<CommandData> { token: Issued<Terms>): Set<CommandData> {
val consumedCommands = super.verify(tx, inputs, outputs, commands, token) val consumedCommands = super.verify(tx, inputs, outputs, commands, token)
val command = commands.requireSingleCommand<Commands.Issue>() commands.requireSingleCommand<Commands.Issue>()
val timestamp = tx.timestamp val timestamp = tx.timestamp
val time = timestamp?.before ?: throw IllegalArgumentException("Issuances must be timestamped") val time = timestamp?.before ?: throw IllegalArgumentException("Issuances must be timestamped")
@ -170,8 +173,8 @@ class CommercialPaper : Contract {
interface Commands : CommandData { interface Commands : CommandData {
class Move : TypeOnlyCommandData(), Commands class Move : TypeOnlyCommandData(), Commands
data class Redeem(val notary: Party) : Commands class Redeem : TypeOnlyCommandData(), Commands
data class Issue(val notary: Party, override val nonce: Long = random63BitValue()) : IssueCommand, Commands data class Issue(override val nonce: Long = random63BitValue()) : IssueCommand, Commands
} }
/** /**
@ -181,7 +184,7 @@ class CommercialPaper : Contract {
*/ */
fun generateIssue(issuance: PartyAndReference, faceValue: Amount<Issued<Currency>>, maturityDate: Instant, notary: Party): TransactionBuilder { fun generateIssue(issuance: PartyAndReference, faceValue: Amount<Issued<Currency>>, maturityDate: Instant, notary: Party): TransactionBuilder {
val state = TransactionState(State(issuance, issuance.party.owningKey, faceValue, maturityDate), notary) val state = TransactionState(State(issuance, issuance.party.owningKey, faceValue, maturityDate), notary)
return TransactionType.General.Builder(notary = notary).withItems(state, Command(Commands.Issue(notary), issuance.party.owningKey)) return TransactionType.General.Builder(notary = notary).withItems(state, Command(Commands.Issue(), issuance.party.owningKey))
} }
/** /**
@ -206,7 +209,7 @@ class CommercialPaper : Contract {
val amount = paper.state.data.faceValue.let { amount -> Amount(amount.quantity, amount.token.product) } val amount = paper.state.data.faceValue.let { amount -> Amount(amount.quantity, amount.token.product) }
Cash().generateSpend(tx, amount, paper.state.data.owner, wallet) Cash().generateSpend(tx, amount, paper.state.data.owner, wallet)
tx.addInputState(paper) tx.addInputState(paper)
tx.addCommand(CommercialPaper.Commands.Redeem(paper.state.notary), paper.state.data.owner) tx.addCommand(CommercialPaper.Commands.Redeem(), paper.state.data.owner)
} }
} }

View File

@ -1,11 +1,14 @@
package com.r3corda.contracts package com.r3corda.contracts
import com.r3corda.contracts.asset.Cash
import com.r3corda.contracts.asset.InsufficientBalanceException
import com.r3corda.contracts.asset.sumCashBy import com.r3corda.contracts.asset.sumCashBy
import com.r3corda.core.contracts.* import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.NullPublicKey import com.r3corda.core.crypto.NullPublicKey
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.SecureHash import com.r3corda.core.crypto.SecureHash
import com.r3corda.core.crypto.toStringShort import com.r3corda.core.crypto.toStringShort
import com.r3corda.core.node.services.Wallet
import com.r3corda.core.utilities.Emoji import com.r3corda.core.utilities.Emoji
import java.security.PublicKey import java.security.PublicKey
import java.time.Instant import java.time.Instant
@ -30,8 +33,7 @@ class CommercialPaperLegacy : Contract {
val maturityDate: Instant val maturityDate: Instant
) : OwnableState, ICommercialPaperState { ) : OwnableState, ICommercialPaperState {
override val contract = CP_LEGACY_PROGRAM_ID override val contract = CP_LEGACY_PROGRAM_ID
override val participants: List<PublicKey> override val participants = listOf(owner)
get() = listOf(owner)
fun withoutOwner() = copy(owner = NullPublicKey) fun withoutOwner() = copy(owner = NullPublicKey)
override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner)) override fun withNewOwner(newOwner: PublicKey) = Pair(Commands.Move(), copy(owner = newOwner))
@ -46,11 +48,11 @@ class CommercialPaperLegacy : Contract {
} }
interface Commands : CommandData { interface Commands : CommandData {
class Move: TypeOnlyCommandData(), Commands class Move : TypeOnlyCommandData(), Commands
data class Redeem(val notary: Party) : Commands class Redeem : TypeOnlyCommandData(), Commands
// We don't need a nonce in the issue command, because the issuance.reference field should already be unique per CP. // We don't need a nonce in the issue command, because the issuance.reference field should already be unique per CP.
// However, nothing in the platform enforces that uniqueness: it's up to the issuer. // However, nothing in the platform enforces that uniqueness: it's up to the issuer.
data class Issue(val notary: Party) : Commands class Issue : TypeOnlyCommandData(), Commands
} }
override fun verify(tx: TransactionForContract) { override fun verify(tx: TransactionForContract) {
@ -74,8 +76,8 @@ class CommercialPaperLegacy : Contract {
} }
} }
// Redemption of the paper requires movement of on-ledger cash.
is Commands.Redeem -> { is Commands.Redeem -> {
// Redemption of the paper requires movement of on-ledger cash.
val input = inputs.single() val input = inputs.single()
val received = tx.outputs.sumCashBy(input.owner) val received = tx.outputs.sumCashBy(input.owner)
val time = timestamp?.after ?: throw IllegalArgumentException("Redemptions must be timestamped") val time = timestamp?.after ?: throw IllegalArgumentException("Redemptions must be timestamped")
@ -97,6 +99,7 @@ class CommercialPaperLegacy : Contract {
"output values sum to more than the inputs" by (output.faceValue.quantity > 0) "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) "the maturity date is not in the past" by (time < output.maturityDate)
// Don't allow an existing CP state to be replaced by this issuance. // 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. // 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" by inputs.isEmpty()
} }
@ -107,4 +110,25 @@ class CommercialPaperLegacy : Contract {
} }
} }
} }
fun generateIssue(issuance: PartyAndReference, faceValue: Amount<Issued<Currency>>, maturityDate: Instant,
notary: Party): TransactionBuilder {
val state = State(issuance, issuance.party.owningKey, faceValue, maturityDate)
return TransactionBuilder(notary = notary).withItems(state, Command(Commands.Issue(), issuance.party.owningKey))
}
fun generateMove(tx: TransactionBuilder, paper: StateAndRef<State>, newOwner: PublicKey) {
tx.addInputState(paper)
tx.addOutputState(paper.state.data.withOwner(newOwner))
tx.addCommand(Command(Commands.Move(), paper.state.data.owner))
}
@Throws(InsufficientBalanceException::class)
fun generateRedeem(tx: TransactionBuilder, paper: StateAndRef<State>, wallet: Wallet) {
// Add the cash movement using the states in our wallet.
Cash().generateSpend(tx, paper.state.data.faceValue.withoutIssuer(),
paper.state.data.owner, wallet.statesOfType<Cash.State>())
tx.addInputState(paper)
tx.addCommand(Command(Commands.Redeem(), paper.state.data.owner))
}
} }

View File

@ -18,10 +18,8 @@ abstract class AbstractIssue<in S: ContractState, T: Any>(
val sum: List<S>.() -> Amount<Issued<T>>, val sum: List<S>.() -> Amount<Issued<T>>,
val sumOrZero: List<S>.(token: Issued<T>) -> Amount<Issued<T>> val sumOrZero: List<S>.(token: Issued<T>) -> Amount<Issued<T>>
) : GroupClause<S, Issued<T>> { ) : GroupClause<S, Issued<T>> {
override val ifMatched: MatchBehaviour override val ifMatched = MatchBehaviour.END
get() = MatchBehaviour.END override val ifNotMatched = MatchBehaviour.CONTINUE
override val ifNotMatched: MatchBehaviour
get() = MatchBehaviour.CONTINUE
override fun verify(tx: TransactionForContract, override fun verify(tx: TransactionForContract,
inputs: List<S>, inputs: List<S>,

View File

@ -17,6 +17,8 @@ import java.util.*
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
import kotlin.test.assertTrue import kotlin.test.assertTrue
// TODO: The generate functions aren't tested by these tests: add them.
interface ICommercialPaperTestTemplate { interface ICommercialPaperTestTemplate {
fun getPaper(): ICommercialPaperState fun getPaper(): ICommercialPaperState
fun getIssueCommand(notary: Party): CommandData fun getIssueCommand(notary: Party): CommandData
@ -32,8 +34,8 @@ class JavaCommercialPaperTest() : ICommercialPaperTestTemplate {
TEST_TX_TIME + 7.days TEST_TX_TIME + 7.days
) )
override fun getIssueCommand(notary: Party): CommandData = JavaCommercialPaper.Commands.Issue(notary) override fun getIssueCommand(notary: Party): CommandData = JavaCommercialPaper.Commands.Issue()
override fun getRedeemCommand(notary: Party): CommandData = JavaCommercialPaper.Commands.Redeem(notary) override fun getRedeemCommand(notary: Party): CommandData = JavaCommercialPaper.Commands.Redeem()
override fun getMoveCommand(): CommandData = JavaCommercialPaper.Commands.Move() override fun getMoveCommand(): CommandData = JavaCommercialPaper.Commands.Move()
} }
@ -45,8 +47,8 @@ class KotlinCommercialPaperTest() : ICommercialPaperTestTemplate {
maturityDate = TEST_TX_TIME + 7.days maturityDate = TEST_TX_TIME + 7.days
) )
override fun getIssueCommand(notary: Party): CommandData = CommercialPaper.Commands.Issue(notary) override fun getIssueCommand(notary: Party): CommandData = CommercialPaper.Commands.Issue()
override fun getRedeemCommand(notary: Party): CommandData = CommercialPaper.Commands.Redeem(notary) override fun getRedeemCommand(notary: Party): CommandData = CommercialPaper.Commands.Redeem()
override fun getMoveCommand(): CommandData = CommercialPaper.Commands.Move() override fun getMoveCommand(): CommandData = CommercialPaper.Commands.Move()
} }
@ -58,8 +60,8 @@ class KotlinCommercialPaperLegacyTest() : ICommercialPaperTestTemplate {
maturityDate = TEST_TX_TIME + 7.days maturityDate = TEST_TX_TIME + 7.days
) )
override fun getIssueCommand(notary: Party): CommandData = CommercialPaperLegacy.Commands.Issue(notary) override fun getIssueCommand(notary: Party): CommandData = CommercialPaperLegacy.Commands.Issue()
override fun getRedeemCommand(notary: Party): CommandData = CommercialPaperLegacy.Commands.Redeem(notary) override fun getRedeemCommand(notary: Party): CommandData = CommercialPaperLegacy.Commands.Redeem()
override fun getMoveCommand(): CommandData = CommercialPaperLegacy.Commands.Move() override fun getMoveCommand(): CommandData = CommercialPaperLegacy.Commands.Move()
} }

View File

@ -93,7 +93,7 @@ class TwoPartyTradeProtocolTests {
bobNode.services.fillWithSomeTestCash(2000.DOLLARS) bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey, val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, notaryNode.info.identity, null).second 1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null).second
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey, notaryNode.storage.myLegalIdentityKey) insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey, notaryNode.storage.myLegalIdentityKey)
@ -144,7 +144,7 @@ class TwoPartyTradeProtocolTests {
bobNode.services.fillWithSomeTestCash(2000.DOLLARS) bobNode.services.fillWithSomeTestCash(2000.DOLLARS)
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey, val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, notaryNode.info.identity, null).second 1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, null).second
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey) insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
val buyerSessionID = random63BitValue() val buyerSessionID = random63BitValue()
@ -262,7 +262,7 @@ class TwoPartyTradeProtocolTests {
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public).second val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public).second
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode.services) val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode.services)
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey, val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, notaryNode.info.identity, attachmentID).second 1200.DOLLARS `issued by` DUMMY_CASH_ISSUER, attachmentID).second
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey) val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
val buyerSessionID = random63BitValue() val buyerSessionID = random63BitValue()
@ -373,7 +373,7 @@ class TwoPartyTradeProtocolTests {
val bobKey = bobNode.keyManagement.freshKey() val bobKey = bobNode.keyManagement.freshKey()
val bobsBadCash = fillUpForBuyer(bobError, bobKey.public).second val bobsBadCash = fillUpForBuyer(bobError, bobKey.public).second
val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.storage.myLegalIdentity.owningKey, val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.storage.myLegalIdentity.owningKey,
1200.DOLLARS `issued by` issuer, notaryNode.info.identity, null).second 1200.DOLLARS `issued by` issuer, null).second
insertFakeTransactions(bobsBadCash, bobNode.services, bobNode.storage.myLegalIdentityKey, bobNode.storage.myLegalIdentityKey) insertFakeTransactions(bobsBadCash, bobNode.services, bobNode.storage.myLegalIdentityKey, bobNode.storage.myLegalIdentityKey)
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey) insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
@ -479,13 +479,12 @@ class TwoPartyTradeProtocolTests {
withError: Boolean, withError: Boolean,
owner: PublicKey, owner: PublicKey,
amount: Amount<Issued<Currency>>, amount: Amount<Issued<Currency>>,
notary: Party,
attachmentID: SecureHash?): Pair<Wallet, List<WireTransaction>> { attachmentID: SecureHash?): Pair<Wallet, List<WireTransaction>> {
val ap = transaction { val ap = transaction {
output("alice's paper") { output("alice's paper") {
CommercialPaper.State(MEGA_CORP.ref(1, 2, 3), owner, amount, TEST_TX_TIME + 7.days) CommercialPaper.State(MEGA_CORP.ref(1, 2, 3), owner, amount, TEST_TX_TIME + 7.days)
} }
command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue(notary) } command(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
if (!withError) if (!withError)
timestamp(time = TEST_TX_TIME) timestamp(time = TEST_TX_TIME)
if (attachmentID != null) if (attachmentID != null)
@ -522,6 +521,4 @@ class TwoPartyTradeProtocolTests {
data class Add(val transaction: SignedTransaction) : TxRecord data class Add(val transaction: SignedTransaction) : TxRecord
data class Get(val id: SecureHash) : TxRecord data class Get(val id: SecureHash) : TxRecord
} }
} }