mirror of
https://github.com/corda/corda.git
synced 2025-06-22 09:08:49 +00:00
Add issuer to cash amounts
Add issuer of a cash when referring to amounts of cash (except for the very few cases where the issuer is not important, such as when referring to aggregated totals across a set of issuers). Replaces CommonCashState with TokenDefinition, as a more accurate reflection of what the class represents.
This commit is contained in:
@ -5,6 +5,9 @@ import com.google.common.util.concurrent.ListenableFuture
|
||||
import com.r3corda.contracts.CommercialPaper
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.contracts.SignedTransaction
|
||||
import com.r3corda.core.contracts.`issued by`
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.generateKeyPair
|
||||
import com.r3corda.core.days
|
||||
import com.r3corda.core.random63BitValue
|
||||
import com.r3corda.core.seconds
|
||||
@ -29,7 +32,7 @@ class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwo
|
||||
WalletFiller.fillWithSomeTestCash(buyer.services, notary.info.identity, 1500.DOLLARS)
|
||||
|
||||
val issuance = run {
|
||||
val tx = CommercialPaper().generateIssue(seller.info.identity.ref(1, 2, 3), 1100.DOLLARS, Instant.now() + 10.days, notary.info.identity)
|
||||
val tx = CommercialPaper().generateIssue(1100.DOLLARS `issued by` seller.info.identity.ref(1, 2, 3), Instant.now() + 10.days, notary.info.identity)
|
||||
tx.setTime(Instant.now(), notary.info.identity, 30.seconds)
|
||||
tx.signWith(notary.storage.myLegalIdentityKey)
|
||||
tx.signWith(seller.storage.myLegalIdentityKey)
|
||||
@ -37,11 +40,13 @@ class TradeSimulation(runAsync: Boolean, latencyInjector: InMemoryMessagingNetwo
|
||||
}
|
||||
seller.services.storageService.validatedTransactions.addTransaction(issuance)
|
||||
|
||||
val cashIssuerKey = generateKeyPair()
|
||||
val amount = 1000.DOLLARS `issued by` Party("Big friendly bank", cashIssuerKey.public).ref(1)
|
||||
val sessionID = random63BitValue()
|
||||
val buyerProtocol = TwoPartyTradeProtocol.Buyer(seller.net.myAddress, notary.info.identity,
|
||||
1000.DOLLARS, CommercialPaper.State::class.java, sessionID)
|
||||
amount, CommercialPaper.State::class.java, sessionID)
|
||||
val sellerProtocol = TwoPartyTradeProtocol.Seller(buyer.net.myAddress, notary.info,
|
||||
issuance.tx.outRef(0), 1000.DOLLARS, seller.storage.myLegalIdentityKey, sessionID)
|
||||
issuance.tx.outRef(0), amount, seller.storage.myLegalIdentityKey, sessionID)
|
||||
|
||||
linkConsensus(listOf(buyer, seller, notary), sellerProtocol)
|
||||
linkProtocolProgress(buyer, buyerProtocol)
|
||||
|
@ -2,6 +2,7 @@ package com.r3corda.node.internal.testing
|
||||
|
||||
import com.r3corda.contracts.cash.Cash
|
||||
import com.r3corda.core.contracts.Amount
|
||||
import com.r3corda.core.contracts.Issued
|
||||
import com.r3corda.core.contracts.TransactionBuilder
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.node.ServiceHub
|
||||
@ -35,7 +36,7 @@ object WalletFiller {
|
||||
|
||||
val issuance = TransactionBuilder()
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
cash.generateIssue(issuance, Amount(pennies, howMuch.token), depositRef, freshKey.public, notary)
|
||||
cash.generateIssue(issuance, Amount(pennies, Issued(depositRef, howMuch.token)), freshKey.public, notary)
|
||||
issuance.signWith(myKey)
|
||||
|
||||
return@map issuance.toSignedTransaction(true)
|
||||
|
@ -5,7 +5,6 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.node.services.Wallet
|
||||
import com.r3corda.core.node.services.WalletService
|
||||
import com.r3corda.core.serialization.OpaqueBytes
|
||||
import com.r3corda.core.serialization.SingletonSerializeAsToken
|
||||
import com.r3corda.core.utilities.loggerFor
|
||||
import com.r3corda.core.utilities.trace
|
||||
|
@ -26,7 +26,7 @@ class WalletImpl(override val states: List<StateAndRef<ContractState>>) : Wallet
|
||||
// Select the states we own which are cash, ignore the rest, take the amounts.
|
||||
mapNotNull { (it.state as? Cash.State)?.amount }.
|
||||
// Turn into a Map<Currency, List<Amount>> like { GBP -> (£100, £500, etc), USD -> ($2000, $50) }
|
||||
groupBy { it.token }.
|
||||
groupBy { it.token.product }.
|
||||
// Collapse to Map<Currency, Amount> by summing all the amounts of the same currency together.
|
||||
mapValues { it.value.sumOrThrow() }
|
||||
mapValues { it.value.map { Amount(it.quantity, it.token.product) }.sumOrThrow() }
|
||||
}
|
@ -57,14 +57,14 @@ class TwoPartyTradeProtocolTests {
|
||||
lateinit var net: MockNetwork
|
||||
|
||||
private fun runSeller(smm: StateMachineManager, notary: NodeInfo,
|
||||
otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount<Currency>,
|
||||
otherSide: SingleMessageRecipient, assetToSell: StateAndRef<OwnableState>, price: Amount<Issued<Currency>>,
|
||||
myKeyPair: KeyPair, buyerSessionID: Long): ListenableFuture<SignedTransaction> {
|
||||
val seller = TwoPartyTradeProtocol.Seller(otherSide, notary, assetToSell, price, myKeyPair, buyerSessionID)
|
||||
return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.seller", seller)
|
||||
}
|
||||
|
||||
private fun runBuyer(smm: StateMachineManager, notaryNode: NodeInfo,
|
||||
otherSide: SingleMessageRecipient, acceptablePrice: Amount<Currency>, typeToBuy: Class<out OwnableState>,
|
||||
otherSide: SingleMessageRecipient, acceptablePrice: Amount<Issued<Currency>>, typeToBuy: Class<out OwnableState>,
|
||||
sessionID: Long): ListenableFuture<SignedTransaction> {
|
||||
val buyer = TwoPartyTradeProtocol.Buyer(otherSide, notaryNode.identity, acceptablePrice, typeToBuy, sessionID)
|
||||
return smm.add("${TwoPartyTradeProtocol.TRADE_TOPIC}.buyer", buyer)
|
||||
@ -94,8 +94,9 @@ class TwoPartyTradeProtocolTests {
|
||||
val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY)
|
||||
|
||||
WalletFiller.fillWithSomeTestCash(bobNode.services, DUMMY_NOTARY, 2000.DOLLARS)
|
||||
val issuer = bobNode.services.storageService.myLegalIdentity.ref(0)
|
||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
|
||||
notaryNode.info.identity, null).second
|
||||
1200.DOLLARS `issued by` issuer, notaryNode.info.identity, null).second
|
||||
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey, notaryNode.storage.myLegalIdentityKey)
|
||||
|
||||
@ -106,7 +107,7 @@ class TwoPartyTradeProtocolTests {
|
||||
notaryNode.info,
|
||||
bobNode.net.myAddress,
|
||||
lookup("alice's paper"),
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
ALICE_KEY,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -114,7 +115,7 @@ class TwoPartyTradeProtocolTests {
|
||||
bobNode.smm,
|
||||
notaryNode.info,
|
||||
aliceNode.net.myAddress,
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
CommercialPaper.State::class.java,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -141,12 +142,13 @@ class TwoPartyTradeProtocolTests {
|
||||
val aliceAddr = aliceNode.net.myAddress
|
||||
val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.Handle
|
||||
val networkMapAddr = notaryNode.info
|
||||
val issuer = bobNode.services.storageService.myLegalIdentity.ref(0)
|
||||
|
||||
net.runNetwork() // Clear network map registration messages
|
||||
|
||||
WalletFiller.fillWithSomeTestCash(bobNode.services, DUMMY_NOTARY, 2000.DOLLARS)
|
||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
|
||||
notaryNode.info.identity, null).second
|
||||
1200.DOLLARS `issued by` issuer, notaryNode.info.identity, null).second
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
|
||||
|
||||
val buyerSessionID = random63BitValue()
|
||||
@ -156,7 +158,7 @@ class TwoPartyTradeProtocolTests {
|
||||
notaryNode.info,
|
||||
bobAddr,
|
||||
lookup("alice's paper"),
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
ALICE_KEY,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -164,7 +166,7 @@ class TwoPartyTradeProtocolTests {
|
||||
bobNode.smm,
|
||||
notaryNode.info,
|
||||
aliceAddr,
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
CommercialPaper.State::class.java,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -260,10 +262,11 @@ class TwoPartyTradeProtocolTests {
|
||||
}
|
||||
val attachmentID = aliceNode.storage.attachments.importAttachment(ByteArrayInputStream(stream.toByteArray()))
|
||||
|
||||
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public).second
|
||||
val issuer = MEGA_CORP.ref(1)
|
||||
val bobsFakeCash = fillUpForBuyer(false, bobNode.keyManagement.freshKey().public, issuer).second
|
||||
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode.services)
|
||||
val alicesFakePaper = fillUpForSeller(false, aliceNode.storage.myLegalIdentity.owningKey,
|
||||
notaryNode.info.identity, attachmentID).second
|
||||
1200.DOLLARS `issued by` issuer, notaryNode.info.identity, attachmentID).second
|
||||
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
|
||||
|
||||
val buyerSessionID = random63BitValue()
|
||||
@ -275,7 +278,7 @@ class TwoPartyTradeProtocolTests {
|
||||
notaryNode.info,
|
||||
bobNode.net.myAddress,
|
||||
lookup("alice's paper"),
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
ALICE_KEY,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -283,7 +286,7 @@ class TwoPartyTradeProtocolTests {
|
||||
bobNode.smm,
|
||||
notaryNode.info,
|
||||
aliceNode.net.myAddress,
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
CommercialPaper.State::class.java,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -366,13 +369,15 @@ class TwoPartyTradeProtocolTests {
|
||||
val notaryNode = net.createNotaryNode(DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
|
||||
val aliceNode = net.createPartyNode(notaryNode.info, ALICE.name, ALICE_KEY)
|
||||
val bobNode = net.createPartyNode(notaryNode.info, BOB.name, BOB_KEY)
|
||||
val issuer = MEGA_CORP.ref(1, 2, 3)
|
||||
|
||||
val aliceAddr = aliceNode.net.myAddress
|
||||
val bobAddr = bobNode.net.myAddress as InMemoryMessagingNetwork.Handle
|
||||
|
||||
val bobKey = bobNode.keyManagement.freshKey()
|
||||
val bobsBadCash = fillUpForBuyer(bobError, bobKey.public).second
|
||||
val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.storage.myLegalIdentity.owningKey, notaryNode.info.identity, null).second
|
||||
val alicesFakePaper = fillUpForSeller(aliceError, aliceNode.storage.myLegalIdentity.owningKey,
|
||||
1200.DOLLARS `issued by` issuer, notaryNode.info.identity, null).second
|
||||
|
||||
insertFakeTransactions(bobsBadCash, bobNode.services, bobNode.storage.myLegalIdentityKey, bobNode.storage.myLegalIdentityKey)
|
||||
insertFakeTransactions(alicesFakePaper, aliceNode.services, aliceNode.storage.myLegalIdentityKey)
|
||||
@ -386,7 +391,7 @@ class TwoPartyTradeProtocolTests {
|
||||
notaryNode.info,
|
||||
bobAddr,
|
||||
lookup("alice's paper"),
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
ALICE_KEY,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -394,7 +399,7 @@ class TwoPartyTradeProtocolTests {
|
||||
bobNode.smm,
|
||||
notaryNode.info,
|
||||
aliceAddr,
|
||||
1000.DOLLARS,
|
||||
1000.DOLLARS `issued by` issuer,
|
||||
CommercialPaper.State::class.java,
|
||||
buyerSessionID
|
||||
)
|
||||
@ -423,14 +428,16 @@ class TwoPartyTradeProtocolTests {
|
||||
return signed.associateBy { it.id }
|
||||
}
|
||||
|
||||
private fun TransactionGroupDSL<ContractState>.fillUpForBuyer(withError: Boolean, owner: PublicKey = BOB_PUBKEY): Pair<Wallet, List<WireTransaction>> {
|
||||
private fun TransactionGroupDSL<ContractState>.fillUpForBuyer(withError: Boolean,
|
||||
owner: PublicKey = BOB_PUBKEY,
|
||||
issuer: PartyAndReference = MEGA_CORP.ref(1)): Pair<Wallet, List<WireTransaction>> {
|
||||
// Bob (Buyer) has some cash he got from the Bank of Elbonia, Alice (Seller) has some commercial paper she
|
||||
// wants to sell to Bob.
|
||||
|
||||
val eb1 = transaction {
|
||||
// Issued money to itself.
|
||||
output("elbonian money 1") { 800.DOLLARS.CASH `issued by` MEGA_CORP `owned by` MEGA_CORP_PUBKEY }
|
||||
output("elbonian money 2") { 1000.DOLLARS.CASH `issued by` MEGA_CORP `owned by` MEGA_CORP_PUBKEY }
|
||||
output("elbonian money 1") { 800.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
|
||||
output("elbonian money 2") { 1000.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY }
|
||||
if (!withError)
|
||||
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Issue() }
|
||||
timestamp(TEST_TX_TIME)
|
||||
@ -439,14 +446,14 @@ class TwoPartyTradeProtocolTests {
|
||||
// Bob gets some cash onto the ledger from BoE
|
||||
val bc1 = transaction {
|
||||
input("elbonian money 1")
|
||||
output("bob cash 1") { 800.DOLLARS.CASH `issued by` MEGA_CORP `owned by` owner }
|
||||
output("bob cash 1") { 800.DOLLARS.CASH `issued by` issuer `owned by` owner }
|
||||
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||
}
|
||||
|
||||
val bc2 = transaction {
|
||||
input("elbonian money 2")
|
||||
output("bob cash 2") { 300.DOLLARS.CASH `issued by` MEGA_CORP `owned by` owner }
|
||||
output { 700.DOLLARS.CASH `issued by` MEGA_CORP `owned by` MEGA_CORP_PUBKEY } // Change output.
|
||||
output("bob cash 2") { 300.DOLLARS.CASH `issued by` issuer `owned by` owner }
|
||||
output { 700.DOLLARS.CASH `issued by` issuer `owned by` MEGA_CORP_PUBKEY } // Change output.
|
||||
arg(MEGA_CORP_PUBKEY) { Cash.Commands.Move() }
|
||||
}
|
||||
|
||||
@ -454,10 +461,14 @@ class TwoPartyTradeProtocolTests {
|
||||
return Pair(wallet, listOf(eb1, bc1, bc2))
|
||||
}
|
||||
|
||||
private fun TransactionGroupDSL<ContractState>.fillUpForSeller(withError: Boolean, owner: PublicKey, notary: Party, attachmentID: SecureHash?): Pair<Wallet, List<WireTransaction>> {
|
||||
private fun TransactionGroupDSL<ContractState>.fillUpForSeller(withError: Boolean,
|
||||
owner: PublicKey,
|
||||
amount: Amount<Issued<Currency>>,
|
||||
notary: Party,
|
||||
attachmentID: SecureHash?): Pair<Wallet, List<WireTransaction>> {
|
||||
val ap = transaction {
|
||||
output("alice's paper") {
|
||||
CommercialPaper.State(MEGA_CORP.ref(1, 2, 3), owner, 1200.DOLLARS, TEST_TX_TIME + 7.days, notary)
|
||||
CommercialPaper.State(MEGA_CORP.ref(1, 2, 3), owner, amount, TEST_TX_TIME + 7.days, notary)
|
||||
}
|
||||
arg(MEGA_CORP_PUBKEY) { CommercialPaper.Commands.Issue() }
|
||||
if (!withError)
|
||||
|
@ -2,20 +2,23 @@ package com.r3corda.node.services
|
||||
|
||||
import com.r3corda.contracts.cash.Cash
|
||||
import com.r3corda.contracts.testing.CASH
|
||||
import com.r3corda.contracts.testing.`issued by`
|
||||
import com.r3corda.contracts.testing.`owned by`
|
||||
import com.r3corda.core.bd
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.contracts.Fix
|
||||
import com.r3corda.core.contracts.TransactionBuilder
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.generateKeyPair
|
||||
import com.r3corda.core.testing.ALICE_PUBKEY
|
||||
import com.r3corda.core.testing.MEGA_CORP
|
||||
import com.r3corda.core.testing.MEGA_CORP_KEY
|
||||
import com.r3corda.core.utilities.BriefLogFormatter
|
||||
import com.r3corda.node.internal.testing.MockNetwork
|
||||
import com.r3corda.node.services.clientapi.NodeInterestRates
|
||||
import com.r3corda.protocols.RatesFixProtocol
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import com.r3corda.protocols.RatesFixProtocol
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
@ -29,6 +32,9 @@ class NodeInterestRatesTest {
|
||||
EURIBOR 2016-03-15 2M = 0.111
|
||||
""".trimIndent())
|
||||
|
||||
val DUMMY_CASH_ISSUER_KEY = generateKeyPair()
|
||||
val DUMMY_CASH_ISSUER = Party("Cash issuer", DUMMY_CASH_ISSUER_KEY.public)
|
||||
|
||||
val oracle = NodeInterestRates.Oracle(MEGA_CORP, MEGA_CORP_KEY).apply { knownFixes = TEST_DATA }
|
||||
|
||||
@Test fun `query successfully`() {
|
||||
@ -111,5 +117,5 @@ class NodeInterestRatesTest {
|
||||
assertEquals("0.678".bd, fix.value)
|
||||
}
|
||||
|
||||
private fun makeTX() = TransactionBuilder(outputs = mutableListOf(1000.DOLLARS.CASH `owned by` ALICE_PUBKEY))
|
||||
private fun makeTX() = TransactionBuilder(outputs = mutableListOf(1000.DOLLARS.CASH `issued by` DUMMY_CASH_ISSUER `owned by` ALICE_PUBKEY))
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.r3corda.node.services
|
||||
|
||||
import com.r3corda.contracts.cash.Cash
|
||||
import com.r3corda.core.contracts.`issued by`
|
||||
import com.r3corda.core.contracts.DOLLARS
|
||||
import com.r3corda.core.contracts.TransactionBuilder
|
||||
import com.r3corda.core.contracts.USD
|
||||
@ -51,13 +52,13 @@ class NodeWalletServiceTest {
|
||||
assertEquals(3, w.states.size)
|
||||
|
||||
val state = w.states[0].state as Cash.State
|
||||
assertEquals(services.storageService.myLegalIdentity, state.deposit.party)
|
||||
assertEquals(services.storageService.myLegalIdentityKey.public, state.deposit.party.owningKey)
|
||||
assertEquals(29.01.DOLLARS, state.amount)
|
||||
val myIdentity = services.storageService.myLegalIdentity
|
||||
val myPartyRef = myIdentity.ref(ref)
|
||||
assertEquals(29.01.DOLLARS `issued by` myPartyRef, state.amount)
|
||||
assertEquals(ALICE_PUBKEY, state.owner)
|
||||
|
||||
assertEquals(33.34.DOLLARS, (w.states[2].state as Cash.State).amount)
|
||||
assertEquals(35.61.DOLLARS, (w.states[1].state as Cash.State).amount)
|
||||
assertEquals(33.34.DOLLARS `issued by` myPartyRef, (w.states[2].state as Cash.State).amount)
|
||||
assertEquals(35.61.DOLLARS `issued by` myPartyRef, (w.states[1].state as Cash.State).amount)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -67,20 +68,20 @@ class NodeWalletServiceTest {
|
||||
// A tx that sends us money.
|
||||
val freshKey = services.keyManagementService.freshKey()
|
||||
val usefulTX = TransactionBuilder().apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS, MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY)
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
val myOutput = usefulTX.verifyToLedgerTransaction(MOCK_IDENTITY_SERVICE, MockStorageService().attachments).outRef<Cash.State>(0)
|
||||
|
||||
// A tx that spends our money.
|
||||
val spendTX = TransactionBuilder().apply {
|
||||
Cash().generateSpend(this, 80.DOLLARS, BOB_PUBKEY, listOf(myOutput))
|
||||
Cash().generateSpend(this, 80.DOLLARS `issued by` MEGA_CORP.ref(1), BOB_PUBKEY, listOf(myOutput))
|
||||
signWith(freshKey)
|
||||
}.toSignedTransaction()
|
||||
|
||||
// A tx that doesn't send us anything.
|
||||
val irrelevantTX = TransactionBuilder().apply {
|
||||
Cash().generateIssue(this, 100.DOLLARS, MEGA_CORP.ref(1), BOB_KEY.public, DUMMY_NOTARY)
|
||||
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), BOB_KEY.public, DUMMY_NOTARY)
|
||||
signWith(MEGA_CORP_KEY)
|
||||
}.toSignedTransaction()
|
||||
|
||||
|
Reference in New Issue
Block a user