From f19df50351824d4c3e611e4fcb22a1dded89945c Mon Sep 17 00:00:00 2001 From: sofusmortensen Date: Tue, 6 Dec 2016 15:38:56 +0000 Subject: [PATCH] universal: simplied Actions squashing condition and actors together (suggested by Simon Peyton-Jones) --- .../corda/contracts/universal/Arrangement.kt | 3 +- .../contracts/universal/ContractFunctions.kt | 2 +- .../net/corda/contracts/universal/Literal.kt | 6 +- .../corda/contracts/universal/Perceivable.kt | 17 +++++- .../net/corda/contracts/universal/README.md | 7 +-- .../contracts/universal/UniversalContract.kt | 20 ++++--- .../net/corda/contracts/universal/Util.kt | 47 ++++++++++++---- .../net/corda/contracts/universal/Cap.kt | 56 +++++++++---------- .../net/corda/contracts/universal/Caplet.kt | 8 +-- .../contracts/universal/ContractDefinition.kt | 42 +++++++------- .../contracts/universal/FXFwdTimeOption.kt | 2 +- .../net/corda/contracts/universal/FXSwap.kt | 16 +++--- .../net/corda/contracts/universal/IRS.kt | 26 ++++----- .../corda/contracts/universal/RollOutTests.kt | 12 ++-- .../net/corda/contracts/universal/Swaption.kt | 34 +++++------ .../contracts/universal/ZeroCouponBond.kt | 6 +- .../net/corda/contracts/universal/examples.kt | 10 ++-- 17 files changed, 177 insertions(+), 137 deletions(-) diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/Arrangement.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/Arrangement.kt index 6c0c8be647..0b4713da58 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/Arrangement.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/Arrangement.kt @@ -30,8 +30,7 @@ data class Obligation(val amount: Perceivable, val currency: Currenc // The ``And`` combinator cannot be root in a arrangement. data class And(val arrangements: Set) : Arrangement -data class Action(val name: String, val condition: Perceivable, - val actors: Set, val arrangement: Arrangement) +data class Action(val name: String, val condition: Perceivable, val arrangement: Arrangement) // An action combinator. This declares a list of named action that can be taken by anyone of the actors given that // _condition_ is met. If the action is performed the arrangement state transitions into the specified arrangement. diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/ContractFunctions.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/ContractFunctions.kt index 694a6e0fae..63b816c111 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/ContractFunctions.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/ContractFunctions.kt @@ -27,5 +27,5 @@ fun fx_swap(expiry: String, notional: BigDecimal, strike: BigDecimal, fun fx_swap2(expiry: String, notional: Long, strike: Double, foreignCurrency: Currency, domesticCurrency: Currency, partyA: Party, partyB: Party) = - Action("execute", after(expiry), setOf(partyA, partyB), + Action("execute", after(expiry) and (signedBy(partyA) or signedBy(partyB)), swap(partyA, BigDecimal(notional * strike), domesticCurrency, partyB, BigDecimal(notional), foreignCurrency)) diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/Literal.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/Literal.kt index 416216f146..c028dc02e9 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/Literal.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/Literal.kt @@ -150,7 +150,7 @@ class ActionBuilder(val actors: Set) { fun String.givenThat(condition: Perceivable, init: ContractBuilder.() -> Arrangement): Action { val b = ContractBuilder() b.init() - val a = Action(this, condition, actors, b.final()) + val a = Action(this, condition and signedByOneOf(actors), b.final()) actions.add(a) return a } @@ -159,7 +159,7 @@ class ActionBuilder(val actors: Set) { val This = this return object : GivenThatResolve { override fun resolve(contract: Arrangement) { - actions.add(Action(This, condition, actors, contract)) + actions.add(Action(This, condition and signedByOneOf(actors), contract)) } } } @@ -167,7 +167,7 @@ class ActionBuilder(val actors: Set) { infix fun String.anytime(init: ContractBuilder.() -> Unit): Action { val b = ContractBuilder() b.init() - val a = Action(this, const(true), actors, b.final()) + val a = Action(this, signedByOneOf(actors), b.final()) actions.add(a) return a } diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt index 91cc5f0927..86a465e7ce 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/Perceivable.kt @@ -2,6 +2,7 @@ package net.corda.contracts.universal import net.corda.core.contracts.BusinessCalendar import net.corda.core.contracts.Tenor +import net.corda.core.crypto.Party import java.math.BigDecimal import java.time.Instant import java.time.LocalDate @@ -40,7 +41,9 @@ data class Const(val value: T) : Perceivable { value!!.hashCode() } -fun const(k: T) = Const(k) +fun const(k: T) : Perceivable = Const(k) + +// fun const(b: Boolean) : Perceivable = Const(b) data class Max(val args: Set>) : Perceivable @@ -70,6 +73,18 @@ class EndDate : Perceivable { } } +data class ActorPerceivable(val actor: Party) : Perceivable +fun signedBy(actor: Party) : Perceivable = ActorPerceivable(actor) + +fun signedByOneOf(actors: Collection): Perceivable = + if (actors.size == 0) + const(true) + else + actors.drop(1).fold(signedBy(actors.first())) { total, next -> total or signedBy(next) } + + + + /** * Perceivable based on time */ diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/README.md b/experimental/src/main/kotlin/net/corda/contracts/universal/README.md index 8323d1425d..e1876b6056 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/README.md +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/README.md @@ -47,11 +47,8 @@ A base contract representing debt of X amount of currency CCY from party A to pa #### ``And contract1 ... contractN`` A combinator over a list of contracts. Each contract in list will create a separate independent contract state. The ``And`` combinator cannot be root in a contract. -#### ``Action name, condition, actors, contract`` -An action combinator. This declares a named action that can be taken by anyone of the actors given that _condition_ is met. If the action is performed the contract state transitions into the specificed contract. - -#### ``Or action1 ... actionN`` -A combinator that can only be used on action contracts. This means only one of the action can be executed. Should any one action be executed, all other actions are discarded. +#### ``Action [name, condition, contract]`` +An action combinator. This declares a list of named actions, only one can be taken and only if the condition is satisfied. If the action is performed the contract state transitions into the specificed contract. #### ``RollOut startDate endDate frequency contractTemplate`` A combinator for rolling out a date sequence using specified template diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt index 298f18115b..4da73834c3 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/UniversalContract.kt @@ -40,13 +40,14 @@ class UniversalContract : Contract { fun eval(tx: TransactionForContract, expr: Perceivable): Boolean = when (expr) { is PerceivableAnd -> eval(tx, expr.left) && eval(tx, expr.right) - is PerceivableOr -> eval(tx, expr.right) || eval(tx, expr.right) + is PerceivableOr -> eval(tx, expr.left) || eval(tx, expr.right) is Const -> expr.value is TimePerceivable -> when (expr.cmp) { Comparison.LTE -> tx.timestamp!!.after!! <= eval(tx, expr.instant) Comparison.GTE -> tx.timestamp!!.before!! >= eval(tx, expr.instant) else -> throw NotImplementedError("eval special") } + is ActorPerceivable -> tx.commands.single().signers.contains(expr.actor.owningKey) else -> throw NotImplementedError("eval - Boolean - " + expr.javaClass.name) } @@ -130,6 +131,9 @@ class UniversalContract : Contract { is PerceivableOperation -> PerceivableOperation(replaceStartEnd(p.left, start, end), p.op, replaceStartEnd(p.right, start, end)) is Interest -> Interest(replaceStartEnd(p.amount, start, end), p.dayCountConvention, replaceStartEnd(p.interest, start, end), replaceStartEnd(p.start, start, end), replaceStartEnd(p.end, start, end)) as Perceivable is Fixing -> Fixing(p.source, replaceStartEnd(p.date, start, end), p.tenor) as Perceivable + is PerceivableAnd -> (replaceStartEnd(p.left, start, end) and replaceStartEnd(p.right, start, end)) as Perceivable + is PerceivableOr -> (replaceStartEnd(p.left, start, end) or replaceStartEnd(p.right, start, end)) as Perceivable + is ActorPerceivable -> p else -> throw NotImplementedError("replaceStartEnd " + p.javaClass.name) } @@ -138,14 +142,14 @@ class UniversalContract : Contract { is And -> And(arrangement.arrangements.map { replaceStartEnd(it, start, end) }.toSet()) is Zero -> arrangement is Obligation -> Obligation(replaceStartEnd(arrangement.amount, start, end), arrangement.currency, arrangement.from, arrangement.to) - is Actions -> Actions(arrangement.actions.map { Action(it.name, replaceStartEnd(it.condition, start, end), it.actors, replaceStartEnd(it.arrangement, start, end)) }.toSet()) + is Actions -> Actions(arrangement.actions.map { Action(it.name, replaceStartEnd(it.condition, start, end), replaceStartEnd(it.arrangement, start, end)) }.toSet()) is Continuation -> arrangement else -> throw NotImplementedError("replaceStartEnd " + arrangement.javaClass.name) } fun replaceNext(arrangement: Arrangement, nextReplacement: RollOut): Arrangement = when (arrangement) { - is Actions -> Actions(arrangement.actions.map { Action(it.name, it.condition, it.actors, replaceNext(it.arrangement, nextReplacement)) }.toSet()) + is Actions -> Actions(arrangement.actions.map { Action(it.name, it.condition, replaceNext(it.arrangement, nextReplacement)) }.toSet()) is And -> And(arrangement.arrangements.map { replaceNext(it, nextReplacement) }.toSet()) is Obligation -> arrangement is Zero -> arrangement @@ -155,7 +159,7 @@ class UniversalContract : Contract { fun removeNext(arrangement: Arrangement): Arrangement = when (arrangement) { - is Actions -> Actions(arrangement.actions.map { Action(it.name, it.condition, it.actors, removeNext(it.arrangement)) }.toSet()) + is Actions -> Actions(arrangement.actions.map { Action(it.name, it.condition, removeNext(it.arrangement)) }.toSet()) is And -> { val a = arrangement.arrangements.map { removeNext(it) }.filter { it != zero } if (a.count() > 1) @@ -200,7 +204,8 @@ class UniversalContract : Contract { requireThat { "action must be timestamped" by (tx.timestamp != null) - "action must be authorized" by (cmd.signers.any { action.actors.any { party -> party.owningKey == it } }) + // "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)) } @@ -290,8 +295,7 @@ class UniversalContract : Contract { fun replaceFixing(tx: TransactionForContract, arr: Action, fixings: Map, unusedFixings: MutableSet) = - Action(arr.name, replaceFixing(tx, arr.condition, fixings, unusedFixings), - arr.actors, replaceFixing(tx, arr.arrangement, fixings, unusedFixings)) + Action(arr.name, replaceFixing(tx, arr.condition, fixings, unusedFixings), replaceFixing(tx, arr.arrangement, fixings, unusedFixings)) fun replaceFixing(tx: TransactionForContract, arr: Arrangement, fixings: Map, unusedFixings: MutableSet): Arrangement = @@ -299,7 +303,7 @@ class UniversalContract : Contract { is Zero -> arr is And -> And(arr.arrangements.map { replaceFixing(tx, it, fixings, unusedFixings) }.toSet()) is Obligation -> Obligation(replaceFixing(tx, arr.amount, fixings, unusedFixings), arr.currency, arr.from, arr.to) - is Actions -> Actions(arr.actions.map { Action(it.name, it.condition, it.actors, replaceFixing(tx, it.arrangement, fixings, unusedFixings)) }.toSet()) + is Actions -> Actions(arr.actions.map { Action(it.name, it.condition, replaceFixing(tx, it.arrangement, fixings, unusedFixings)) }.toSet()) is RollOut -> RollOut(arr.startDate, arr.endDate, arr.frequency, replaceFixing(tx, arr.template, fixings, unusedFixings)) is Continuation -> arr else -> throw NotImplementedError("replaceFixing - " + arr.javaClass.name) diff --git a/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt b/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt index 8e71e579da..4c99f57469 100644 --- a/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt +++ b/experimental/src/main/kotlin/net/corda/contracts/universal/Util.kt @@ -2,6 +2,7 @@ package net.corda.contracts.universal import com.google.common.collect.ImmutableSet import com.google.common.collect.Sets +import com.sun.tools.corba.se.idl.InvalidArgument import net.corda.core.contracts.Frequency import net.corda.core.crypto.CompositeKey import net.corda.core.crypto.Party @@ -12,6 +13,15 @@ fun Instant.toLocalDate(): LocalDate = LocalDate.ofEpochDay(this.epochSecond / 6 fun LocalDate.toInstant(): Instant = Instant.ofEpochSecond(this.toEpochDay() * 60 * 60 * 24) +private fun signingParties(perceivable: Perceivable) : ImmutableSet = + when (perceivable) { + is ActorPerceivable -> ImmutableSet.of( perceivable.actor.owningKey ) + is PerceivableAnd -> Sets.union( signingParties( perceivable.left ), signingParties(perceivable.right) ).immutableCopy() + is PerceivableOr -> Sets.union( signingParties( perceivable.left ), signingParties(perceivable.right) ).immutableCopy() + is TimePerceivable -> ImmutableSet.of() + else -> throw IllegalArgumentException("signingParties " + perceivable) + } + private fun liablePartiesVisitor(arrangement: Arrangement): ImmutableSet = when (arrangement) { is Zero -> ImmutableSet.of() @@ -25,17 +35,19 @@ private fun liablePartiesVisitor(arrangement: Arrangement): ImmutableSet throw IllegalArgumentException("liableParties " + arrangement) } -private fun liablePartiesVisitor(action: Action): ImmutableSet = - if (action.actors.size != 1) - liablePartiesVisitor(action.arrangement) - else - Sets.difference(liablePartiesVisitor(action.arrangement), ImmutableSet.of(action.actors.single())).immutableCopy() +private fun liablePartiesVisitor(action: Action): ImmutableSet { + val actors = signingParties(action.condition) + return if (actors.size != 1) + liablePartiesVisitor(action.arrangement) + else + Sets.difference(liablePartiesVisitor(action.arrangement), ImmutableSet.of(actors.single())).immutableCopy() +} /** Returns list of potentially liable parties for a given contract */ fun liableParties(contract: Arrangement): Set = liablePartiesVisitor(contract) private fun involvedPartiesVisitor(action: Action): Set = - Sets.union(involvedPartiesVisitor(action.arrangement), action.actors.map { it.owningKey }.toSet()).immutableCopy() + Sets.union(involvedPartiesVisitor(action.arrangement), signingParties(action.condition)).immutableCopy() private fun involvedPartiesVisitor(arrangement: Arrangement): ImmutableSet = when (arrangement) { @@ -51,11 +63,25 @@ private fun involvedPartiesVisitor(arrangement: Arrangement): ImmutableSet = involvedPartiesVisitor(arrangement) +fun replaceParty(perceivable: Perceivable, from: Party, to: Party): Perceivable = + when (perceivable) { + is ActorPerceivable -> + if (perceivable.actor == from) + signedBy(to) + else + perceivable + is PerceivableAnd -> replaceParty(perceivable.left, from, to) and replaceParty(perceivable.right, from, to) + is PerceivableOr -> replaceParty(perceivable.left, from, to) or replaceParty(perceivable.right, from, to) + is TimePerceivable -> perceivable + else -> throw InvalidArgument("replaceParty " + perceivable) + } + fun replaceParty(action: Action, from: Party, to: Party): Action = - if (action.actors.contains(from)) { - Action(action.name, action.condition, action.actors - from + to, replaceParty(action.arrangement, from, to)) - } else - Action(action.name, action.condition, action.actors, replaceParty(action.arrangement, from, to)) + Action(action.name, replaceParty(action.condition, from, to), replaceParty(action.arrangement, from, to)) + //if (action.actors.contains(from)) { + // Action(action.name, action.condition, action.actors - from + to, replaceParty(action.arrangement, from, to)) + //} else + // Action(action.name, action.condition, replaceParty(action.arrangement, from, to)) fun replaceParty(arrangement: Arrangement, from: Party, to: Party): Arrangement = when (arrangement) { is Zero -> arrangement @@ -184,7 +210,6 @@ fun debugCompare(arrLeft: Arrangement, arrRight: Arrangement) { arrLeft.actions.zip(arrRight.actions).forEach { debugCompare(it.first.arrangement, it.second.arrangement) debugCompare(it.first.condition, it.second.condition) - debugCompare(it.first.actors, it.second.actors) debugCompare(it.first.name, it.second.name) return } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt index 622cccc87f..422f0f5d4f 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/Cap.kt @@ -22,16 +22,16 @@ class Cap { val contractInitial = arrange { rollOut("2016-09-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) highStreetBank.owes(acmeCorp, floating - fixed, currency) next() } } - acmeCorp.may { - "skip".anytime { + acmeCorp may { + "skip" anytime { next() } } @@ -41,23 +41,23 @@ class Cap { val contractAfterFixingFirst = arrange { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime() { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating1 = interest(notional, "act/365", 1.0.bd, "2016-09-01", "2017-03-01") val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-09-01", "2017-03-01") highStreetBank.owes(acmeCorp, floating1 - fixed1, currency) rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) highStreetBank.owes(acmeCorp, floating - fixed, currency) next() } } - acmeCorp.may { - "skip".anytime { + acmeCorp may { + "skip" anytime { next() } } @@ -65,20 +65,20 @@ class Cap { } } } - acmeCorp.may { - "skip".anytime { + acmeCorp may { + "skip" anytime { rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) highStreetBank.owes(acmeCorp, floating - fixed, currency) next() } } - acmeCorp.may { - "skip".anytime { + acmeCorp may { + "skip" anytime { next() } } @@ -91,15 +91,15 @@ class Cap { val contractAfterFixingFinal = arrange { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime() { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating1 = interest(notional, "act/365", 1.0.bd, "2017-03-01", "2017-09-01") val fixed1 = interest(notional, "act/365", 0.5.bd, "2017-03-01", "2017-09-01") highStreetBank.owes(acmeCorp, floating1 - fixed1, currency) } } - acmeCorp.may { - "skip".anytime { + acmeCorp may { + "skip" anytime { } } } @@ -108,16 +108,16 @@ class Cap { val contractAfterExecutionFirst = arrange { rollOut("2017-03-01".ld, "2017-09-01".ld, Frequency.SemiAnnual) { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) highStreetBank.owes(acmeCorp, floating - fixed, currency) next() } } - acmeCorp.may { - "skip".anytime { + acmeCorp may { + "skip" anytime { next() } } @@ -144,8 +144,8 @@ class Cap { val limit = variable(150.K) }) { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) val payout = min(floating - fixed) @@ -153,8 +153,8 @@ class Cap { next(vars.limit to vars.limit - payout) } } - acmeCorp.may { - "skip".anytime { + acmeCorp may { + "skip" anytime { next() } } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt index e27ca43ce8..52afd64969 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/Caplet.kt @@ -19,8 +19,8 @@ class Caplet { val contract = arrange { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime() { + (acmeCorp or highStreetBank) may { + "exercise" anytime { val floating = interest(notional, "act/365", fix("LIBOR", tradeDate, Tenor("6M")), "2016-04-01", "2016-10-01") val fixed = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-10-01") highStreetBank.owes(acmeCorp, (floating - fixed).plus(), currency) @@ -31,8 +31,8 @@ class Caplet { val contractFixed = arrange { actions { - (acmeCorp or highStreetBank).may { - "exercise".anytime() { + (acmeCorp or highStreetBank) may { + "exercise" anytime { 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") highStreetBank.owes(acmeCorp, (floating - fixed).plus(), currency) diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt index 7405856c20..3e458e826e 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/ContractDefinition.kt @@ -25,12 +25,12 @@ class ContractDefinition { val cds_contract = arrange { actions { - acmeCorp.may { + acmeCorp may { "payout".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) { highStreetBank.owes(acmeCorp, 1.M, USD) } } - highStreetBank.may { + highStreetBank may { "expire".givenThat(after("2017-09-01")) { zero } @@ -41,13 +41,13 @@ class ContractDefinition { val american_fx_option = arrange { actions { - acmeCorp.may { - "exercise".anytime { - highStreetBank.owes(acmeCorp, 1.M, EUR) - acmeCorp.owes(highStreetBank, 1200.K, USD) + acmeCorp may { + "exercise" anytime { + highStreetBank.owes(acmeCorp, 1.M, USD) + acmeCorp.owes(highStreetBank, 1070.K, EUR) } } - highStreetBank.may { + highStreetBank may { "expire".givenThat(after("2017-09-01")) { zero } @@ -58,19 +58,19 @@ class ContractDefinition { val european_fx_option = arrange { actions { - acmeCorp.may { - "exercise".anytime { + acmeCorp may { + "exercise" anytime { actions { - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { "execute".givenThat(after("2017-09-01")) { - highStreetBank.owes(acmeCorp, 1.M, EUR) - acmeCorp.owes(highStreetBank, 1200.K, USD) + highStreetBank.owes(acmeCorp, 1.M, USD) + acmeCorp.owes(highStreetBank, 1070.K, EUR) } } } } } - highStreetBank.may { + highStreetBank may { "expire".givenThat(after("2017-09-01")) { zero } @@ -83,10 +83,10 @@ class ContractDefinition { fun `builder problem - should not compile`() { val arr = arrange { actions { - acmeCorp.may { - "execute".anytime { - acmeCorp.may { - "problem".anytime { + acmeCorp may { + "execute" anytime { + acmeCorp may { + "problem" anytime { highStreetBank.gives(acmeCorp, 1.M, USD) } } @@ -106,11 +106,11 @@ class ContractDefinition { fun `builder problem - legal`() { val arr = arrange { actions { - acmeCorp.may { - "execute".anytime { + acmeCorp may { + "execute" anytime { actions { - acmeCorp.may { - "problem".anytime { + acmeCorp may { + "problem" anytime { highStreetBank.owes(acmeCorp, 1.M, USD) } } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt index e68e987388..3a857d53ad 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/FXFwdTimeOption.kt @@ -11,7 +11,7 @@ class FXFwdTimeOption val initialContract = arrange { val swap = arrange { - highStreetBank.owes(acmeCorp, 1200.K, EUR) + highStreetBank.owes(acmeCorp, 1070.K, EUR) acmeCorp.owes(highStreetBank, 1.M, USD) } val maturity = "2018-06-01".ld diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt index 0732da318c..c59a635532 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/FXSwap.kt @@ -14,22 +14,22 @@ class FXSwap { actions { (acmeCorp or highStreetBank) may { "execute".givenThat(after("2017-09-01")) { - highStreetBank.owes(acmeCorp, 1200.K, USD) - acmeCorp.owes(highStreetBank, 1.M, EUR) + highStreetBank.owes(acmeCorp, 1070.K, EUR) + acmeCorp.owes(highStreetBank, 1.M, USD) } } } } - val transfer1 = arrange { highStreetBank.owes(acmeCorp, 1200.K, USD) } - val transfer2 = arrange { acmeCorp.owes(highStreetBank, 1.M, EUR) } + val transfer1 = arrange { highStreetBank.owes(acmeCorp, 1070.K, EUR) } + val transfer2 = arrange { acmeCorp.owes(highStreetBank, 1.M, USD) } val outState1 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transfer1) val outState2 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transfer2) - val transferBad1 = arrange { highStreetBank.owes(acmeCorp, 1200.K, GBP) } // wrong currency - val transferBad2 = arrange { acmeCorp.owes(highStreetBank, 900.K, EUR) } // wrong amount - val transferBad3 = arrange { highStreetBank.owes(highStreetBank, 1.M, EUR) } // wrong party + val transferBad1 = arrange { highStreetBank.owes(acmeCorp, 1070.K, USD) } // wrong currency + val transferBad2 = arrange { acmeCorp.owes(highStreetBank, 900.K, USD) } // wrong amount + val transferBad3 = arrange { highStreetBank.owes(highStreetBank, 1070.K, EUR) } // wrong party val outStateBad1 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transferBad1) val outStateBad2 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transferBad2) @@ -108,7 +108,7 @@ class FXSwap { timestamp(TEST_TX_TIME_1) command(momAndPop.owningKey) { UniversalContract.Commands.Action("execute") } - this `fails with` "action must be authorized" + this `fails with` "condition must be met" } } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt index 269959ba90..a5f13d7272 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/IRS.kt @@ -33,15 +33,15 @@ class IRS { val contractInitial = arrange { rollOut("2016-09-01".ld, "2018-09-01".ld, Frequency.Quarterly) { actions { - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) - "pay floating".anytime { + "pay floating" anytime { highStreetBank.owes(acmeCorp, floating - fixed, currency) next() } - "pay fixed".anytime { + "pay fixed" anytime { highStreetBank.owes(acmeCorp, fixed - floating, currency) next() } @@ -51,11 +51,11 @@ class IRS { } val contractAfterFixingFirst = arrange { actions { - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { val floating = interest(notional, "act/365", 1.0.bd, "2016-09-01", "2016-12-01") val fixed = interest(notional, "act/365", 0.5.bd, "2016-09-01", "2016-12-01") - "pay floating".anytime { + "pay floating" anytime { highStreetBank.owes(acmeCorp, floating - fixed, currency) rollOut("2016-12-01".ld, "2018-09-01".ld, Frequency.Quarterly) { actions { @@ -63,11 +63,11 @@ class IRS { val nextFloating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val nextFixed = interest(notional, "act/365", 0.5.bd, start, end) - "pay floating".anytime { + "pay floating" anytime { highStreetBank.owes(acmeCorp, nextFloating - nextFixed, currency) next() } - "pay fixed".anytime { + "pay fixed" anytime { highStreetBank.owes(acmeCorp, nextFixed - nextFloating, currency) next() } @@ -75,7 +75,7 @@ class IRS { } } } - "pay fixed".anytime { + "pay fixed" anytime { highStreetBank.owes(acmeCorp, fixed - floating, currency) rollOut("2016-12-01".ld, "2018-09-01".ld, Frequency.Quarterly) { actions { @@ -83,11 +83,11 @@ class IRS { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) - "pay floating".anytime { + "pay floating" anytime { highStreetBank.owes(acmeCorp, floating - fixed, currency) next() } - "pay fixed".anytime { + "pay fixed" anytime { highStreetBank.owes(acmeCorp, fixed - floating, currency) next() } @@ -102,15 +102,15 @@ class IRS { val contractAfterExecutionFirst = arrange { rollOut("2016-12-01".ld, "2018-09-01".ld, Frequency.Quarterly) { actions { - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("3M")), start, end) val fixed = interest(notional, "act/365", 0.5.bd, start, end) - "pay floating".anytime { + "pay floating" anytime { highStreetBank.owes(acmeCorp, floating - fixed, currency) next() } - "pay fixed".anytime { + "pay fixed" anytime { highStreetBank.owes(acmeCorp, fixed - floating, currency) next() } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt index 8fde42d114..13d09b9f7a 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/RollOutTests.kt @@ -67,7 +67,7 @@ class RollOutTests { val contract_action1 = arrange { actions { highStreetBank may { - "do it".anytime { + "do it" anytime { highStreetBank.owes(acmeCorp, 10.K, USD) } } @@ -76,7 +76,7 @@ class RollOutTests { val contract_action2 = arrange { actions { highStreetBank may { - "do it".anytime { + "do it" anytime { highStreetBank.owes(acmeCorp, 10.K, USD) } } @@ -85,14 +85,14 @@ class RollOutTests { val contract_and1 = arrange { actions { highStreetBank may { - "do it".anytime { + "do it" anytime { highStreetBank.owes(acmeCorp, 10.K, USD) } } } actions { acmeCorp may { - "do it".anytime { + "do it" anytime { acmeCorp.owes(momAndPop, 10.K, USD) } } @@ -103,14 +103,14 @@ class RollOutTests { val contract_and2 = arrange { actions { highStreetBank may { - "do it".anytime { + "do it" anytime { highStreetBank.owes(acmeCorp, 10.K, USD) } } } actions { acmeCorp may { - "do it".anytime { + "do it" anytime { acmeCorp.owes(momAndPop, 10.K, USD) } } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt index 432545f385..f354f3dcac 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/Swaption.kt @@ -9,19 +9,19 @@ class Swaption { val dreary_contract = arrange { actions { - (highStreetBank or acmeCorp).may { + (highStreetBank or acmeCorp) may { "proceed".givenThat(after("01/07/2015")) { highStreetBank.owes(acmeCorp, libor(notional, "01/04/2015", "01/07/2015"), currency) acmeCorp.owes(highStreetBank, interest(notional, "act/365", coupon, "01/04/2015", "01/07/2015"), currency) actions { - (highStreetBank or acmeCorp).may { + (highStreetBank or acmeCorp) may { "proceed".givenThat(after("01/10/2015")) { highStreetBank.owes(acmeCorp, libor(notional, "01/07/2015", "01/10/2015"), currency) acmeCorp.owes(highStreetBank, interest(notional, "act/365", coupon, "01/07/2015", "01/10/2015"), currency) actions { - (highStreetBank or acmeCorp).may { - "dummy".anytime { zero } + (highStreetBank or acmeCorp) may { + "dummy" anytime { zero } // etc ... } } @@ -29,16 +29,16 @@ class Swaption { } } actions { - acmeCorp.may { - "cancel".anytime { + acmeCorp may { + "cancel" anytime { acmeCorp.owes(highStreetBank, 10.K, USD) } } } } } - acmeCorp.may { - "cancel".anytime { + acmeCorp may { + "cancel" anytime { acmeCorp.owes(highStreetBank, 10.K, USD) } } @@ -49,15 +49,15 @@ class Swaption { val elegant_contract = arrange { rollOut("01/04/2015".ld, "01/04/2025".ld, Frequency.Quarterly) { actions { - (highStreetBank or acmeCorp).may { + (highStreetBank or acmeCorp) may { "proceed".givenThat(after(start)) { highStreetBank.owes(acmeCorp, libor(notional, start, end), currency) acmeCorp.owes(highStreetBank, interest(notional, "act/365", coupon, start, end), currency) next() } } - acmeCorp.may { - "cancel".anytime { + acmeCorp may { + "cancel" anytime { acmeCorp.owes(highStreetBank, 10.K, currency) } } @@ -72,12 +72,12 @@ class Swaption { val cap = variable(150.K) }) { actions { - acmeCorp.may { + acmeCorp may { "exercise".givenThat(before(end)) { val payout = (EUR / USD - strike).plus() * notional actions { - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { "proceed".givenThat(after(end)) { highStreetBank.owes(acmeCorp, payout, USD) next(vars.cap to vars.cap - payout) @@ -86,7 +86,7 @@ class Swaption { } } } - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { "proceedWithoutExercise".givenThat(after(end)) { next() } @@ -100,12 +100,12 @@ class Swaption { val uses = variable(4) }) { actions { - acmeCorp.may { + acmeCorp may { "exercise".givenThat(before(end)) { val payout = (EUR / USD - strike).plus() * notional actions { - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { "proceed".givenThat(after(end)) { highStreetBank.owes(acmeCorp, payout, currency) next(vars.uses to vars.uses - 1) @@ -114,7 +114,7 @@ class Swaption { } } } - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { "proceedWithoutExercise".givenThat(after(end)) { next() } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt index 22a6f46464..cc30d941a7 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/ZeroCouponBond.kt @@ -9,7 +9,7 @@ class ZeroCouponBond { val contract = arrange { actions { - (acmeCorp or highStreetBank).may { + (acmeCorp or highStreetBank) may { "execute".givenThat(after("2017-09-01")) { highStreetBank.owes(acmeCorp, 100.K, GBP) } @@ -19,7 +19,7 @@ class ZeroCouponBond { val contractMove = arrange { actions { - (momAndPop or highStreetBank).may { + (momAndPop or highStreetBank) may { "execute".givenThat(after("2017-09-01")) { highStreetBank.owes(momAndPop, 100.K, GBP) } @@ -90,7 +90,7 @@ class ZeroCouponBond { timestamp(TEST_TX_TIME_1) command(momAndPop.owningKey) { UniversalContract.Commands.Action("execute") } - this `fails with` "action must be authorized" + this `fails with` "condition must be met" } } diff --git a/experimental/src/test/kotlin/net/corda/contracts/universal/examples.kt b/experimental/src/test/kotlin/net/corda/contracts/universal/examples.kt index a9b23bfd82..0e961d8c3e 100644 --- a/experimental/src/test/kotlin/net/corda/contracts/universal/examples.kt +++ b/experimental/src/test/kotlin/net/corda/contracts/universal/examples.kt @@ -20,8 +20,8 @@ val an_fx_swap = arrange { actions { (acmeCorp or highStreetBank) may { "execute".givenThat(after("2017-09-01")) { - highStreetBank.owes(acmeCorp, 1200.K, USD) - acmeCorp.owes(highStreetBank, 1.M, EUR) + highStreetBank.owes(acmeCorp, 1070.K, EUR) + acmeCorp.owes(highStreetBank, 1.M, USD) } } } @@ -31,8 +31,8 @@ val american_fx_option = arrange { actions { acmeCorp may { "exercise".givenThat(before("2017-09-01")) { - highStreetBank.owes(acmeCorp, 1200.K, USD) - acmeCorp.owes(highStreetBank, 1.M, EUR) + highStreetBank.owes(acmeCorp, 1070.K, EUR) + acmeCorp.owes(highStreetBank, 1.M, USD) } } } @@ -46,7 +46,7 @@ val european_fx_option = arrange { } } (acmeCorp or highStreetBank) may { - "expire".anytime { + "expire" anytime { zero } }