mirror of
https://github.com/corda/corda.git
synced 2025-01-07 05:28:51 +00:00
Universal: example parties renamed
This commit is contained in:
parent
1ceee48696
commit
c7b164897b
@ -12,7 +12,6 @@ import java.util.*
|
|||||||
|
|
||||||
interface Arrangement
|
interface Arrangement
|
||||||
|
|
||||||
|
|
||||||
// A base arrangement with no rights and no obligations. Contract cancellation/termination is a transition to ``Zero``.
|
// A base arrangement with no rights and no obligations. Contract cancellation/termination is a transition to ``Zero``.
|
||||||
class Zero() : Arrangement {
|
class Zero() : Arrangement {
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
@ -28,11 +27,7 @@ class Zero() : Arrangement {
|
|||||||
//
|
//
|
||||||
// todo: should be replaced with something that uses Corda assets and/or cash?
|
// todo: should be replaced with something that uses Corda assets and/or cash?
|
||||||
// todo: should only be allowed to transfer non-negative amounts
|
// todo: should only be allowed to transfer non-negative amounts
|
||||||
data class Transfer(val amount: Perceivable<BigDecimal>, val currency: Currency, val from: Party, val to: Party) : Arrangement {
|
data class Transfer(val amount: Perceivable<BigDecimal>, val currency: Currency, val from: Party, val to: Party) : Arrangement
|
||||||
constructor(amount: BigDecimal, currency: Currency, from: Party, to: Party ) : this(const(amount), currency, from, to)
|
|
||||||
constructor(amount: Amount<Currency>, from: Party, to: Party ) : this(const(BigDecimal(amount.quantity)), amount.token, from, to)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// A combinator over a list of arrangements. Each arrangement in list will create a separate independent arrangement state.
|
// A combinator over a list of arrangements. Each arrangement in list will create a separate independent arrangement state.
|
||||||
// The ``And`` combinator cannot be root in a arrangement.
|
// The ``And`` combinator cannot be root in a arrangement.
|
||||||
|
@ -141,7 +141,7 @@ class UniversalContract : Contract {
|
|||||||
is Transfer -> {
|
is Transfer -> {
|
||||||
val amount = eval(tx, arrangement.amount)
|
val amount = eval(tx, arrangement.amount)
|
||||||
requireThat { "transferred quantity is non-negative" by (amount >= BigDecimal.ZERO) }
|
requireThat { "transferred quantity is non-negative" by (amount >= BigDecimal.ZERO) }
|
||||||
Transfer(amount, arrangement.currency, arrangement.from, arrangement.to)
|
Transfer(const(amount), arrangement.currency, arrangement.from, arrangement.to)
|
||||||
}
|
}
|
||||||
is And -> And(arrangement.arrangements.map { validateImmediateTransfers(tx, it) }.toSet())
|
is And -> And(arrangement.arrangements.map { validateImmediateTransfers(tx, it) }.toSet())
|
||||||
else -> arrangement
|
else -> arrangement
|
||||||
|
@ -24,7 +24,7 @@ open class ContractBuilder {
|
|||||||
val contracts = mutableListOf<Arrangement>()
|
val contracts = mutableListOf<Arrangement>()
|
||||||
|
|
||||||
fun Party.gives(beneficiary: Party, amount: BigDecimal, currency: Currency) : Transfer {
|
fun Party.gives(beneficiary: Party, amount: BigDecimal, currency: Currency) : Transfer {
|
||||||
val c = Transfer(amount, currency, this, beneficiary)
|
val c = Transfer(const(amount), currency, this, beneficiary)
|
||||||
contracts.add( c )
|
contracts.add( c )
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
@ -20,14 +20,14 @@ class Cap {
|
|||||||
|
|
||||||
val contract = arrange {
|
val contract = arrange {
|
||||||
rollOut("2016-04-01", "2017-04-01", Frequency.Quarterly) {
|
rollOut("2016-04-01", "2017-04-01", Frequency.Quarterly) {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"exercise".anytime {
|
"exercise".anytime {
|
||||||
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("6M")), start, end)
|
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("6M")), start, end)
|
||||||
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
|
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
|
||||||
wileECoyote.gives(roadRunner, floating - fixed, currency)
|
highStreetBank.gives(acmeCorp, floating - fixed, currency)
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
} or roadRunner.may {
|
} or acmeCorp.may {
|
||||||
"skip".anytime {
|
"skip".anytime {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
@ -42,15 +42,15 @@ class Cap {
|
|||||||
rollOut("2016-04-01", "2017-04-01", Frequency.Quarterly, object {
|
rollOut("2016-04-01", "2017-04-01", Frequency.Quarterly, object {
|
||||||
val limit = variable(150.K)
|
val limit = variable(150.K)
|
||||||
}) {
|
}) {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"exercise".anytime {
|
"exercise".anytime {
|
||||||
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("6M")), start, end)
|
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("6M")), start, end)
|
||||||
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
|
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
|
||||||
val payout = (floating - fixed).plus()
|
val payout = (floating - fixed).plus()
|
||||||
wileECoyote.gives(roadRunner, payout, currency)
|
highStreetBank.gives(acmeCorp, payout, currency)
|
||||||
next(vars.limit to vars.limit - payout)
|
next(vars.limit to vars.limit - payout)
|
||||||
}
|
}
|
||||||
} or roadRunner.may {
|
} or acmeCorp.may {
|
||||||
"skip".anytime {
|
"skip".anytime {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
@ -67,11 +67,11 @@ class Cap {
|
|||||||
this `fails with` "transaction has a single command"
|
this `fails with` "transaction has a single command"
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Issue() }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
this `fails with` "the transaction is signed by all liable parties"
|
this `fails with` "the transaction is signed by all liable parties"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Issue() }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
|
@ -24,26 +24,26 @@ class Caplet {
|
|||||||
val currency = EUR
|
val currency = EUR
|
||||||
|
|
||||||
val contract = arrange {
|
val contract = arrange {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"exercise".anytime() {
|
"exercise".anytime() {
|
||||||
val floating = interest(notional, "act/365", fix("LIBOR", dt, Tenor("6M")), "2016-04-01", "2016-10-01")
|
val floating = interest(notional, "act/365", fix("LIBOR", dt, Tenor("6M")), "2016-04-01", "2016-10-01")
|
||||||
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
|
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
|
||||||
wileECoyote.gives(roadRunner, (floating - fixed).plus(), currency)
|
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val contractFixed = arrange {
|
val contractFixed = arrange {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"exercise".anytime() {
|
"exercise".anytime() {
|
||||||
val floating = interest(notional, "act/365", 1.0.bd, "2016-04-01", "2016-10-01")
|
val floating = interest(notional, "act/365", 1.0.bd, "2016-04-01", "2016-10-01")
|
||||||
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
|
val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01")
|
||||||
wileECoyote.gives(roadRunner, (floating - fixed).plus(), currency)
|
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val contractFinal = arrange { wileECoyote.gives(roadRunner, 250.K, EUR) }
|
val contractFinal = arrange { highStreetBank.gives(acmeCorp, 250.K, EUR) }
|
||||||
|
|
||||||
val stateStart = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contract)
|
val stateStart = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contract)
|
||||||
|
|
||||||
@ -60,11 +60,11 @@ class Caplet {
|
|||||||
this `fails with` "transaction has a single command"
|
this `fails with` "transaction has a single command"
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Issue() }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
this `fails with` "the transaction is signed by all liable parties"
|
this `fails with` "the transaction is signed by all liable parties"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Issue() }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
@ -78,11 +78,11 @@ class Caplet {
|
|||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
||||||
this `fails with` "action must be defined"
|
this `fails with` "action must be defined"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("exercise") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("exercise") }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
@ -96,38 +96,38 @@ class Caplet {
|
|||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
||||||
this `fails with` "action must be defined"
|
this `fails with` "action must be defined"
|
||||||
}
|
}
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
// wrong source
|
// wrong source
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBORx", dt, Tenor("6M")), 1.0.bd))) }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBORx", dt, Tenor("6M")), 1.0.bd))) }
|
||||||
|
|
||||||
this `fails with` "relevant fixing must be included"
|
this `fails with` "relevant fixing must be included"
|
||||||
}
|
}
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
// wrong date
|
// wrong date
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt.plusYears(1), Tenor("6M")), 1.0.bd))) }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt.plusYears(1), Tenor("6M")), 1.0.bd))) }
|
||||||
|
|
||||||
this `fails with` "relevant fixing must be included"
|
this `fails with` "relevant fixing must be included"
|
||||||
}
|
}
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
// wrong tenor
|
// wrong tenor
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt, Tenor("3M")), 1.0.bd))) }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt, Tenor("3M")), 1.0.bd))) }
|
||||||
|
|
||||||
this `fails with` "relevant fixing must be included"
|
this `fails with` "relevant fixing must be included"
|
||||||
}
|
}
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt, Tenor("6M")), 1.5.bd))) }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt, Tenor("6M")), 1.5.bd))) }
|
||||||
|
|
||||||
this `fails with` "output state does not reflect fix command"
|
this `fails with` "output state does not reflect fix command"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt, Tenor("6M")), 1.0.bd))) }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", dt, Tenor("6M")), 1.0.bd))) }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,9 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Test parties
|
// Test parties
|
||||||
val roadRunner = Party("Road Runner", generateKeyPair().public)
|
val acmeCorp = Party("ACME Corporation", generateKeyPair().public)
|
||||||
val wileECoyote = Party("Wile E. Coyote", generateKeyPair().public)
|
val highStreetBank = Party("High Street Bank", generateKeyPair().public)
|
||||||
val porkyPig = Party("Porky Pig", generateKeyPair().public)
|
val momAndPop = Party("Mom and Pop", generateKeyPair().public)
|
||||||
|
|
||||||
val acmeCorporationHasDefaulted = DummyPerceivable<Boolean>()
|
val acmeCorporationHasDefaulted = DummyPerceivable<Boolean>()
|
||||||
|
|
||||||
@ -28,11 +28,11 @@ class ContractDefinition {
|
|||||||
|
|
||||||
|
|
||||||
val cds_contract = arrange {
|
val cds_contract = arrange {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"payout".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
|
"payout".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1.M, USD)
|
highStreetBank.gives(acmeCorp, 1.M, USD)
|
||||||
}
|
}
|
||||||
} or wileECoyote.may {
|
} or highStreetBank.may {
|
||||||
"expire".givenThat(after("2017-09-01")) {
|
"expire".givenThat(after("2017-09-01")) {
|
||||||
zero
|
zero
|
||||||
}
|
}
|
||||||
@ -41,12 +41,12 @@ class ContractDefinition {
|
|||||||
|
|
||||||
|
|
||||||
val american_fx_option = arrange {
|
val american_fx_option = arrange {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"exercise".anytime {
|
"exercise".anytime {
|
||||||
wileECoyote.gives(roadRunner, 1.M, EUR)
|
highStreetBank.gives(acmeCorp, 1.M, EUR)
|
||||||
roadRunner.gives(wileECoyote, 1200.K, USD)
|
acmeCorp.gives(highStreetBank, 1200.K, USD)
|
||||||
}
|
}
|
||||||
} or wileECoyote.may {
|
} or highStreetBank.may {
|
||||||
"expire".givenThat(after("2017-09-01")) {
|
"expire".givenThat(after("2017-09-01")) {
|
||||||
zero
|
zero
|
||||||
}
|
}
|
||||||
@ -55,16 +55,16 @@ class ContractDefinition {
|
|||||||
|
|
||||||
|
|
||||||
val european_fx_option = arrange {
|
val european_fx_option = arrange {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"exercise".anytime {
|
"exercise".anytime {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1.M, EUR)
|
highStreetBank.gives(acmeCorp, 1.M, EUR)
|
||||||
roadRunner.gives(wileECoyote, 1200.K, USD)
|
acmeCorp.gives(highStreetBank, 1200.K, USD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} or wileECoyote.may {
|
} or highStreetBank.may {
|
||||||
"expire".givenThat(after("2017-09-01")) {
|
"expire".givenThat(after("2017-09-01")) {
|
||||||
zero
|
zero
|
||||||
}
|
}
|
||||||
|
@ -15,23 +15,23 @@ class FXSwap {
|
|||||||
val TEST_TX_TIME_TOO_EARLY: Instant get() = Instant.parse("2017-08-31T12:00:00.00Z")
|
val TEST_TX_TIME_TOO_EARLY: Instant get() = Instant.parse("2017-08-31T12:00:00.00Z")
|
||||||
|
|
||||||
val contract = arrange {
|
val contract = arrange {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1200.K, USD)
|
highStreetBank.gives(acmeCorp, 1200.K, USD)
|
||||||
roadRunner.gives(wileECoyote, 1.M, EUR)
|
acmeCorp.gives(highStreetBank, 1.M, EUR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val transfer1 = arrange { wileECoyote.gives(roadRunner, 1200.K, USD) }
|
val transfer1 = arrange { highStreetBank.gives(acmeCorp, 1200.K, USD) }
|
||||||
val transfer2 = arrange { roadRunner.gives(wileECoyote, 1.M, EUR) }
|
val transfer2 = arrange { acmeCorp.gives(highStreetBank, 1.M, EUR) }
|
||||||
|
|
||||||
val outState1 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transfer1 )
|
val outState1 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transfer1 )
|
||||||
val outState2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transfer2 )
|
val outState2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transfer2 )
|
||||||
|
|
||||||
val transferBad1 = arrange { wileECoyote.gives(roadRunner, 1200.K, GBP) } // wrong currency
|
val transferBad1 = arrange { highStreetBank.gives(acmeCorp, 1200.K, GBP) } // wrong currency
|
||||||
val transferBad2 = arrange { roadRunner.gives(wileECoyote, 900.K, EUR) } // wrong amount
|
val transferBad2 = arrange { acmeCorp.gives(highStreetBank, 900.K, EUR) } // wrong amount
|
||||||
val transferBad3 = arrange { wileECoyote.gives(wileECoyote, 1.M, EUR) } // wrong party
|
val transferBad3 = arrange { highStreetBank.gives(highStreetBank, 1.M, EUR) } // wrong party
|
||||||
|
|
||||||
val outStateBad1 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferBad1 )
|
val outStateBad1 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferBad1 )
|
||||||
val outStateBad2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferBad2 )
|
val outStateBad2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferBad2 )
|
||||||
@ -49,15 +49,15 @@ class FXSwap {
|
|||||||
this `fails with` "transaction has a single command"
|
this `fails with` "transaction has a single command"
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Issue() }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
this `fails with` "the transaction is signed by all liable parties"
|
this `fails with` "the transaction is signed by all liable parties"
|
||||||
}
|
}
|
||||||
tweak {
|
tweak {
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Issue() }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
this `fails with` "the transaction is signed by all liable parties"
|
this `fails with` "the transaction is signed by all liable parties"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey, roadRunner.owningKey) { UniversalContract.Commands.Issue() }
|
command(highStreetBank.owningKey, acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
@ -72,11 +72,11 @@ class FXSwap {
|
|||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
||||||
this `fails with` "action must be defined"
|
this `fails with` "action must be defined"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
@ -91,11 +91,11 @@ class FXSwap {
|
|||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
||||||
this `fails with` "action must be defined"
|
this `fails with` "action must be defined"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ class FXSwap {
|
|||||||
output { outState2 }
|
output { outState2 }
|
||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
command(porkyPig.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(momAndPop.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "action must be authorized"
|
this `fails with` "action must be authorized"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ class FXSwap {
|
|||||||
output { outState2 }
|
output { outState2 }
|
||||||
timestamp(TEST_TX_TIME_TOO_EARLY)
|
timestamp(TEST_TX_TIME_TOO_EARLY)
|
||||||
|
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "condition must be met"
|
this `fails with` "condition must be met"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,7 +134,7 @@ class FXSwap {
|
|||||||
output { outState1 }
|
output { outState1 }
|
||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "output state must match action result state"
|
this `fails with` "output state must match action result state"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,7 +147,7 @@ class FXSwap {
|
|||||||
output { outStateBad2 }
|
output { outStateBad2 }
|
||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "output states must match action result state"
|
this `fails with` "output states must match action result state"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +160,7 @@ class FXSwap {
|
|||||||
output { outState2 }
|
output { outState2 }
|
||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "output states must match action result state"
|
this `fails with` "output states must match action result state"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,7 +173,7 @@ class FXSwap {
|
|||||||
output { outStateBad3 }
|
output { outStateBad3 }
|
||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "output states must match action result state"
|
this `fails with` "output states must match action result state"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,28 +17,28 @@ class Swaption {
|
|||||||
val coupon = 1.5.bd
|
val coupon = 1.5.bd
|
||||||
|
|
||||||
val dreary_contract = arrange {
|
val dreary_contract = arrange {
|
||||||
(wileECoyote or roadRunner).may {
|
(highStreetBank or acmeCorp).may {
|
||||||
"proceed".givenThat(after("01/07/2015")) {
|
"proceed".givenThat(after("01/07/2015")) {
|
||||||
wileECoyote.gives(roadRunner, libor(notional, "01/04/2015", "01/07/2015"), currency)
|
highStreetBank.gives(acmeCorp, libor(notional, "01/04/2015", "01/07/2015"), currency)
|
||||||
roadRunner.gives(wileECoyote, interest(notional, "act/365", coupon, "01/04/2015", "01/07/2015"), currency)
|
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, "01/04/2015", "01/07/2015"), currency)
|
||||||
(wileECoyote or roadRunner).may {
|
(highStreetBank or acmeCorp).may {
|
||||||
"proceed".givenThat(after("01/10/2015")) {
|
"proceed".givenThat(after("01/10/2015")) {
|
||||||
wileECoyote.gives(roadRunner, libor(notional, "01/07/2015", "01/10/2015"), currency)
|
highStreetBank.gives(acmeCorp, libor(notional, "01/07/2015", "01/10/2015"), currency)
|
||||||
roadRunner.gives(wileECoyote, interest(notional, "act/365", coupon, "01/07/2015", "01/10/2015"), currency)
|
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, "01/07/2015", "01/10/2015"), currency)
|
||||||
|
|
||||||
(wileECoyote or roadRunner).may {
|
(highStreetBank or acmeCorp).may {
|
||||||
// etc ...
|
// etc ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} or roadRunner.may {
|
} or acmeCorp.may {
|
||||||
"cancel".anytime {
|
"cancel".anytime {
|
||||||
roadRunner.gives(wileECoyote, 10.K, USD)
|
acmeCorp.gives(highStreetBank, 10.K, USD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} or roadRunner.may {
|
} or acmeCorp.may {
|
||||||
"cancel".anytime {
|
"cancel".anytime {
|
||||||
roadRunner.gives(wileECoyote, 10.K, USD)
|
acmeCorp.gives(highStreetBank, 10.K, USD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,15 +46,15 @@ class Swaption {
|
|||||||
|
|
||||||
val elegant_contract = arrange {
|
val elegant_contract = arrange {
|
||||||
rollOut("01/04/2015", "01/04/2025", Frequency.Quarterly) {
|
rollOut("01/04/2015", "01/04/2025", Frequency.Quarterly) {
|
||||||
(wileECoyote or roadRunner).may {
|
(highStreetBank or acmeCorp).may {
|
||||||
"proceed".givenThat(after(start)) {
|
"proceed".givenThat(after(start)) {
|
||||||
wileECoyote.gives(roadRunner, libor(notional, start, end), currency)
|
highStreetBank.gives(acmeCorp, libor(notional, start, end), currency)
|
||||||
roadRunner.gives(wileECoyote, interest(notional, "act/365", coupon, start, end), currency)
|
acmeCorp.gives(highStreetBank, interest(notional, "act/365", coupon, start, end), currency)
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
} or roadRunner.may {
|
} or acmeCorp.may {
|
||||||
"cancel".anytime {
|
"cancel".anytime {
|
||||||
roadRunner.gives(wileECoyote, 10.K, currency)
|
acmeCorp.gives(highStreetBank, 10.K, currency)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,18 +66,18 @@ class Swaption {
|
|||||||
rollOut("01/04/2015", "01/04/2016", Frequency.Quarterly, object {
|
rollOut("01/04/2015", "01/04/2016", Frequency.Quarterly, object {
|
||||||
val cap = variable(150.K)
|
val cap = variable(150.K)
|
||||||
}) {
|
}) {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"exercise".givenThat(before(end)) {
|
"exercise".givenThat(before(end)) {
|
||||||
val payout = (EUR / USD - strike).plus() * notional
|
val payout = (EUR / USD - strike).plus() * notional
|
||||||
|
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"proceed".givenThat(after(end)) {
|
"proceed".givenThat(after(end)) {
|
||||||
wileECoyote.gives(roadRunner, payout, USD)
|
highStreetBank.gives(acmeCorp, payout, USD)
|
||||||
next(vars.cap to vars.cap - payout)
|
next(vars.cap to vars.cap - payout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} or (roadRunner or wileECoyote).may {
|
} or (acmeCorp or highStreetBank).may {
|
||||||
"proceedWithoutExercise".givenThat(after(end)) {
|
"proceedWithoutExercise".givenThat(after(end)) {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
@ -89,18 +89,18 @@ class Swaption {
|
|||||||
rollOut("01/04/2015", "01/04/2016", Frequency.Quarterly, object {
|
rollOut("01/04/2015", "01/04/2016", Frequency.Quarterly, object {
|
||||||
val uses = variable(4)
|
val uses = variable(4)
|
||||||
}) {
|
}) {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"exercise".givenThat(before(end)) {
|
"exercise".givenThat(before(end)) {
|
||||||
val payout = (EUR / USD - strike).plus() * notional
|
val payout = (EUR / USD - strike).plus() * notional
|
||||||
|
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"proceed".givenThat(after(end)) {
|
"proceed".givenThat(after(end)) {
|
||||||
wileECoyote.gives(roadRunner, payout, currency)
|
highStreetBank.gives(acmeCorp, payout, currency)
|
||||||
next(vars.uses to vars.uses - 1)
|
next(vars.uses to vars.uses - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} or (roadRunner or wileECoyote).may {
|
} or (acmeCorp or highStreetBank).may {
|
||||||
"proceedWithoutExercise".givenThat(after(end)) {
|
"proceedWithoutExercise".givenThat(after(end)) {
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
@ -12,26 +12,26 @@ import java.time.Instant
|
|||||||
class ZeroCouponBond {
|
class ZeroCouponBond {
|
||||||
|
|
||||||
val contract = arrange {
|
val contract = arrange {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 100.K, GBP)
|
highStreetBank.gives(acmeCorp, 100.K, GBP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val contractMove = arrange {
|
val contractMove = arrange {
|
||||||
(porkyPig or wileECoyote).may {
|
(momAndPop or highStreetBank).may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(porkyPig, 100.K, GBP)
|
highStreetBank.gives(momAndPop, 100.K, GBP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
|
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
|
||||||
|
|
||||||
val transfer = arrange { wileECoyote.gives(roadRunner, 100.K, GBP) }
|
val transfer = arrange { highStreetBank.gives(acmeCorp, 100.K, GBP) }
|
||||||
val transferWrong = arrange { wileECoyote.gives(roadRunner, 80.K, GBP) }
|
val transferWrong = arrange { highStreetBank.gives(acmeCorp, 80.K, GBP) }
|
||||||
|
|
||||||
val inState = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contract )
|
val inState = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contract )
|
||||||
|
|
||||||
@ -55,11 +55,11 @@ class ZeroCouponBond {
|
|||||||
this `fails with` "transaction has a single command"
|
this `fails with` "transaction has a single command"
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Issue() }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
this `fails with` "the transaction is signed by all liable parties"
|
this `fails with` "the transaction is signed by all liable parties"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Issue() }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Issue() }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
@ -73,11 +73,11 @@ class ZeroCouponBond {
|
|||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
||||||
this `fails with` "action must be defined"
|
this `fails with` "action must be defined"
|
||||||
}
|
}
|
||||||
|
|
||||||
command(wileECoyote.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
|
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ class ZeroCouponBond {
|
|||||||
output { outState }
|
output { outState }
|
||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
command(porkyPig.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(momAndPop.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "action must be authorized"
|
this `fails with` "action must be authorized"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +102,7 @@ class ZeroCouponBond {
|
|||||||
output { outStateWrong }
|
output { outStateWrong }
|
||||||
timestamp(TEST_TX_TIME_1)
|
timestamp(TEST_TX_TIME_1)
|
||||||
|
|
||||||
command(roadRunner.owningKey) { UniversalContract.Commands.Action("execute") }
|
command(acmeCorp.owningKey) { UniversalContract.Commands.Action("execute") }
|
||||||
this `fails with` "output state must match action result state"
|
this `fails with` "output state must match action result state"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,24 +114,24 @@ class ZeroCouponBond {
|
|||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
output { outStateMove }
|
output { outStateMove }
|
||||||
command(roadRunner.owningKey) {
|
command(acmeCorp.owningKey) {
|
||||||
UniversalContract.Commands.Move(roadRunner, porkyPig)
|
UniversalContract.Commands.Move(acmeCorp, momAndPop)
|
||||||
}
|
}
|
||||||
this `fails with` "the transaction is signed by all liable parties"
|
this `fails with` "the transaction is signed by all liable parties"
|
||||||
}
|
}
|
||||||
|
|
||||||
tweak {
|
tweak {
|
||||||
output { inState }
|
output { inState }
|
||||||
command(roadRunner.owningKey, porkyPig.owningKey, wileECoyote.owningKey) {
|
command(acmeCorp.owningKey, momAndPop.owningKey, highStreetBank.owningKey) {
|
||||||
UniversalContract.Commands.Move(roadRunner, porkyPig)
|
UniversalContract.Commands.Move(acmeCorp, momAndPop)
|
||||||
}
|
}
|
||||||
this `fails with` "output state does not reflect move command"
|
this `fails with` "output state does not reflect move command"
|
||||||
}
|
}
|
||||||
|
|
||||||
output { outStateMove}
|
output { outStateMove}
|
||||||
|
|
||||||
command(roadRunner.owningKey, porkyPig.owningKey, wileECoyote.owningKey) {
|
command(acmeCorp.owningKey, momAndPop.owningKey, highStreetBank.owningKey) {
|
||||||
UniversalContract.Commands.Move(roadRunner, porkyPig)
|
UniversalContract.Commands.Move(acmeCorp, momAndPop)
|
||||||
}
|
}
|
||||||
this.verifies()
|
this.verifies()
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,9 @@ import java.util.*
|
|||||||
// various example arrangements using basic syntax
|
// various example arrangements using basic syntax
|
||||||
|
|
||||||
val cds_contract = arrange {
|
val cds_contract = arrange {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"claim".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
|
"claim".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1.M, USD)
|
highStreetBank.gives(acmeCorp, 1.M, USD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,29 +24,29 @@ val cds_contract = arrange {
|
|||||||
// fx swap
|
// fx swap
|
||||||
// both parties have the right to trigger the exchange of cash flows
|
// both parties have the right to trigger the exchange of cash flows
|
||||||
val an_fx_swap = arrange {
|
val an_fx_swap = arrange {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1200.K, USD)
|
highStreetBank.gives(acmeCorp, 1200.K, USD)
|
||||||
roadRunner.gives(wileECoyote, 1.M, EUR)
|
acmeCorp.gives(highStreetBank, 1.M, EUR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val american_fx_option = arrange {
|
val american_fx_option = arrange {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"exercise".givenThat(before("2017-09-01")) {
|
"exercise".givenThat(before("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1200.K, USD)
|
highStreetBank.gives(acmeCorp, 1200.K, USD)
|
||||||
roadRunner.gives(wileECoyote, 1.M, EUR)
|
acmeCorp.gives(highStreetBank, 1.M, EUR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val european_fx_option = arrange {
|
val european_fx_option = arrange {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"exercise".givenThat(before("2017-09-01")) {
|
"exercise".givenThat(before("2017-09-01")) {
|
||||||
fx_swap("2017-09-01", 1.M, 1.2.bd, EUR, USD, roadRunner, wileECoyote)
|
fx_swap("2017-09-01", 1.M, 1.2.bd, EUR, USD, acmeCorp, highStreetBank)
|
||||||
}
|
}
|
||||||
} or (roadRunner or wileECoyote).may {
|
} or (acmeCorp or highStreetBank).may {
|
||||||
"expire".anytime {
|
"expire".anytime {
|
||||||
zero
|
zero
|
||||||
}
|
}
|
||||||
@ -54,18 +54,18 @@ val european_fx_option = arrange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val zero_coupon_bond_1 = arrange {
|
val zero_coupon_bond_1 = arrange {
|
||||||
roadRunner.may {
|
acmeCorp.may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1.M, USD)
|
highStreetBank.gives(acmeCorp, 1.M, USD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// maybe in the presence of negative interest rates you would want other side of contract to be able to take initiative as well
|
// maybe in the presence of negative interest rates you would want other side of contract to be able to take initiative as well
|
||||||
val zero_coupon_bond_2 = arrange {
|
val zero_coupon_bond_2 = arrange {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1.M, USD)
|
highStreetBank.gives(acmeCorp, 1.M, USD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,23 +80,23 @@ val zero_coupon_bond_2 = arrange {
|
|||||||
// Assume observable is using FX fixing
|
// Assume observable is using FX fixing
|
||||||
//
|
//
|
||||||
val no_touch = arrange {
|
val no_touch = arrange {
|
||||||
(roadRunner or wileECoyote).may {
|
(acmeCorp or highStreetBank).may {
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
wileECoyote.gives(roadRunner, 1.M, USD)
|
highStreetBank.gives(acmeCorp, 1.M, USD)
|
||||||
}
|
}
|
||||||
} or wileECoyote.may {
|
} or highStreetBank.may {
|
||||||
"knock out".givenThat(EUR/USD gt 1.3)
|
"knock out".givenThat(EUR/USD gt 1.3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val one_touch = arrange {
|
val one_touch = arrange {
|
||||||
wileECoyote.may {
|
highStreetBank.may {
|
||||||
"expire".givenThat(after("2017-09-01")) {
|
"expire".givenThat(after("2017-09-01")) {
|
||||||
zero
|
zero
|
||||||
}
|
}
|
||||||
} or roadRunner.may {
|
} or acmeCorp.may {
|
||||||
"knock in".givenThat(EUR / USD gt 1.3) {
|
"knock in".givenThat(EUR / USD gt 1.3) {
|
||||||
wileECoyote.gives(roadRunner, 1.M, USD)
|
highStreetBank.gives(acmeCorp, 1.M, USD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user