Minor style tweaks to the universal contract.

This commit is contained in:
Mike Hearn 2016-11-15 19:15:23 +01:00
parent d1b279c2b2
commit 8a680b3726
17 changed files with 139 additions and 225 deletions

5
.idea/modules.xml generated
View File

@ -34,7 +34,10 @@
<module fileurl="file://$PROJECT_DIR$/.idea/modules/finance/isolated/isolated_main.iml" filepath="$PROJECT_DIR$/.idea/modules/finance/isolated/isolated_main.iml" group="finance/isolated" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/finance/isolated/isolated_test.iml" filepath="$PROJECT_DIR$/.idea/modules/finance/isolated/isolated_test.iml" group="finance/isolated" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest.iml" filepath="$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest.iml" group="tools/loadtest" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest.iml" filepath="$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest.iml" group="tools/loadtest" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_main.iml" filepath="$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_main.iml" group="tools/loadtest" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_main.iml" filepath="$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_main.iml" group="tools/loadtest" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_test.iml" filepath="$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_test.iml" group="tools/loadtest" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_test.iml" filepath="$PROJECT_DIR$/.idea/modules/tools/loadtest/loadtest_test.iml" group="tools/loadtest" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/node/node.iml" filepath="$PROJECT_DIR$/.idea/modules/node/node.iml" group="node" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/node/node_integrationTest.iml" filepath="$PROJECT_DIR$/.idea/modules/node/node_integrationTest.iml" group="node" />
@ -57,4 +60,4 @@
<module fileurl="file://$PROJECT_DIR$/.idea/modules/tools/tools_test.iml" filepath="$PROJECT_DIR$/.idea/modules/tools/tools_test.iml" group="tools" />
</modules>
</component>
</project>
</project>

View File

@ -1,17 +1,11 @@
package net.corda.contracts.universal
import net.corda.core.contracts.Amount
import net.corda.core.contracts.Frequency
import net.corda.core.crypto.Party
import net.corda.core.crypto.SecureHash
import java.math.BigDecimal
import java.time.LocalDate
import java.util.*
/**
* Created by sofusmortensen on 23/05/16.
*/
interface Arrangement
// A base arrangement with no rights and no obligations. Contract cancellation/termination is a transition to ``Zero``.
@ -19,6 +13,7 @@ class Zero() : Arrangement {
override fun hashCode(): Int {
return 0
}
override fun equals(other: Any?): Boolean {
return other is Zero
}
@ -27,8 +22,8 @@ class Zero() : Arrangement {
// A basic arrangement representing immediate transfer of Cash - X amount of currency CCY from party A to party B.
// X is an observable of type BigDecimal.
//
// 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 be replaced with something that uses Corda assets and/or cash?
// 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
// A combinator over a list of arrangements. Each arrangement in list will create a separate independent arrangement state.
@ -42,14 +37,9 @@ data class Action(val name: String, val condition: Perceivable<Boolean>,
// _condition_ is met. If the action is performed the arrangement state transitions into the specified arrangement.
data class Actions(val actions: Set<Action>) : Arrangement
// constructor(name: String, condition: Perceivable<Boolean>,
// actor: Party, arrangement: Arrangement)
// Roll out of arrangement
data class RollOut(val startDate: LocalDate, val endDate: LocalDate, val frequency: Frequency, val template: Arrangement) : Arrangement
// Continuation of roll out
// May only be used inside template for RollOut
class Continuation() : Arrangement {
@ -60,13 +50,4 @@ class Continuation() : Arrangement {
override fun equals(other: Any?): Boolean {
return other is Continuation
}
}
// A smart contract template
// todo: handle parameters
//
data class Template(val template: Arrangement)
data class TemplateApplication(val template: SecureHash, val parameters: Map<String, Any>) : Arrangement
data class Context(val arrangement: Arrangement, val parameters: Map<String, Any>) : Arrangement
}

View File

@ -4,15 +4,11 @@ import net.corda.core.crypto.Party
import java.math.BigDecimal
import java.util.*
/**
* Created by sofusmortensen on 23/05/16.
*/
fun swap(partyA: Party, amountA: BigDecimal, currencyA: Currency, partyB: Party, amountB: BigDecimal, currencyB: Currency) =
arrange {
partyA.gives(partyB, amountA, currencyA)
partyB.gives(partyA, amountB, currencyB)
}
arrange {
partyA.gives(partyB, amountA, currencyA)
partyB.gives(partyA, amountB, currencyB)
}
fun fx_swap(expiry: String, notional: BigDecimal, strike: BigDecimal,
foreignCurrency: Currency, domesticCurrency: Currency,

View File

@ -7,14 +7,6 @@ import java.math.BigDecimal
import java.time.LocalDate
import java.util.*
/**
* Created by sofusmortensen on 23/05/16.
*/
// operator fun Long.times(currency: Currency) = Amount(this.toLong(), currency)
// operator fun Double.times(currency: Currency) = Amount(BigDecimal(this.toDouble()), currency)
val Int.M: BigDecimal get() = BigDecimal(this) * BigDecimal(1000000)
val Int.K: BigDecimal get() = BigDecimal(this) * BigDecimal(1000)
@ -34,14 +26,14 @@ class ActionsBuilder {
infix fun Party.may(init: ActionBuilder.() -> Action): Action {
val builder = ActionBuilder(setOf(this))
builder.init()
actions.addAll( builder.actions )
actions.addAll(builder.actions)
return builder.actions.first()
}
infix fun Set<Party>.may(init: ActionBuilder.() -> Action): Action {
val builder = ActionBuilder(this)
builder.init()
actions.addAll( builder.actions )
actions.addAll(builder.actions)
return builder.actions.first()
}
@ -53,7 +45,7 @@ class ActionsBuilder {
open class ContractBuilder {
private val contracts = mutableListOf<Arrangement>()
fun actions(init: ActionsBuilder.() -> Action ) : Arrangement {
fun actions(init: ActionsBuilder.() -> Action): Arrangement {
val b = ActionsBuilder()
b.init()
val c = b.final()
@ -98,12 +90,6 @@ open class ContractBuilder {
fun Set<Party>.may(init: ActionBuilder.() -> Action) {
}
/* fun Party.gives(beneficiary: Party, amount: Perceivable<Long>, currency: Currency) {
contracts.add( Transfer(amount, currency, this, beneficiary))
}*/
// infix fun Arrangement.and(arrangement: Arrangement) = And(setOf(this, arrangement))
val start = StartDate()
val end = EndDate()
@ -155,15 +141,15 @@ interface GivenThatResolve {
class ActionBuilder(val actors: Set<Party>) {
val actions = mutableListOf<Action>()
fun String.givenThat(condition: Perceivable<Boolean>, init: ContractBuilder.() -> Arrangement ) : Action {
fun String.givenThat(condition: Perceivable<Boolean>, init: ContractBuilder.() -> Arrangement): Action {
val b = ContractBuilder()
b.init()
val a = Action(this, condition, actors, b.final() )
actions.add( a )
val a = Action(this, condition, actors, b.final())
actions.add(a)
return a
}
fun String.givenThat(condition: Perceivable<Boolean> ) : GivenThatResolve {
fun String.givenThat(condition: Perceivable<Boolean>): GivenThatResolve {
val This = this
return object : GivenThatResolve {
override fun resolve(contract: Arrangement) {
@ -172,16 +158,16 @@ class ActionBuilder(val actors: Set<Party>) {
}
}
fun String.anytime(init: ContractBuilder.() -> Unit ) : Action {
fun String.anytime(init: ContractBuilder.() -> Unit): Action {
val b = ContractBuilder()
b.init()
val a = Action(this, const(true), actors, b.final() )
actions.add( a )
val a = Action(this, const(true), actors, b.final())
actions.add(a)
return a
}
}
fun arrange(init: ContractBuilder.() -> Unit ) : Arrangement {
fun arrange(init: ContractBuilder.() -> Unit): Arrangement {
val b = ContractBuilder()
b.init()
return b.final()
@ -189,13 +175,11 @@ fun arrange(init: ContractBuilder.() -> Unit ) : Arrangement {
data class Parameter<T>(val initialValue: T) : Perceivable<T>
fun<T> variable(v: T) = Parameter<T>(v)
fun <T> variable(v: T) = Parameter<T>(v)
class RollOutBuilder<T>(val startDate: LocalDate, val endDate: LocalDate, val frequency: Frequency, val vars: T) : ContractBuilder() {
override fun final() =
RollOut(startDate, endDate, frequency, super.final())
}
class Dummy {}

View File

@ -5,13 +5,8 @@ import net.corda.core.contracts.Tenor
import java.math.BigDecimal
import java.time.Instant
import java.time.LocalDate
import java.time.Period
import java.util.*
/**
* Created by sofusmortensen on 23/05/16.
*/
interface Perceivable<T>
enum class Comparison {
@ -45,15 +40,16 @@ data class Const<T>(val value: T) : Perceivable<T> {
value!!.hashCode()
}
fun<T> const(k: T) = Const(k)
fun <T> const(k: T) = Const(k)
data class Max(val args: Set<Perceivable<BigDecimal>>) : Perceivable<BigDecimal>
fun max(vararg args: Perceivable<BigDecimal>) = Max(args.toSet())
data class Min(val args: Set<Perceivable<BigDecimal>>) : Perceivable<BigDecimal>
fun min(vararg args: Perceivable<BigDecimal>) = Min(args.toSet())
//
class StartDate : Perceivable<Instant> {
override fun hashCode(): Int {
return 2
@ -81,8 +77,6 @@ data class TimePerceivable(val cmp: Comparison, val instant: Perceivable<Instant
fun parseDate(str: String) = BusinessCalendar.parseDateFromString(str)
// Instant.parse(str+"T00:00:00Z")!!
fun before(expiry: Perceivable<Instant>) = TimePerceivable(Comparison.LTE, expiry)
fun after(expiry: Perceivable<Instant>) = TimePerceivable(Comparison.GTE, expiry)
fun before(expiry: Instant) = TimePerceivable(Comparison.LTE, const(expiry))
@ -91,9 +85,11 @@ fun before(expiry: String) = TimePerceivable(Comparison.LTE, const(parseDate(exp
fun after(expiry: String) = TimePerceivable(Comparison.GTE, const(parseDate(expiry).toInstant()))
data class PerceivableAnd(val left: Perceivable<Boolean>, val right: Perceivable<Boolean>) : Perceivable<Boolean>
infix fun Perceivable<Boolean>.and(obs: Perceivable<Boolean>) = PerceivableAnd(this, obs)
data class PerceivableOr(val left: Perceivable<Boolean>, val right: Perceivable<Boolean>) : Perceivable<Boolean>
infix fun Perceivable<Boolean>.or(obs: Perceivable<Boolean>) = PerceivableOr(this, obs)
data class CurrencyCross(val foreign: Currency, val domestic: Currency) : Perceivable<BigDecimal>
@ -104,13 +100,13 @@ data class PerceivableComparison<T>(val left: Perceivable<T>, val cmp: Compariso
infix fun Perceivable<BigDecimal>.lt(n: BigDecimal) = PerceivableComparison(this, Comparison.LT, const(n))
infix fun Perceivable<BigDecimal>.gt(n: BigDecimal) = PerceivableComparison(this, Comparison.GT, const(n))
infix fun Perceivable<BigDecimal>.lt(n: Double) = PerceivableComparison(this, Comparison.LT, const( BigDecimal(n) ))
infix fun Perceivable<BigDecimal>.gt(n: Double) = PerceivableComparison(this, Comparison.GT, const( BigDecimal(n) ))
infix fun Perceivable<BigDecimal>.lt(n: Double) = PerceivableComparison(this, Comparison.LT, const(BigDecimal(n)))
infix fun Perceivable<BigDecimal>.gt(n: Double) = PerceivableComparison(this, Comparison.GT, const(BigDecimal(n)))
infix fun Perceivable<BigDecimal>.lte(n: BigDecimal) = PerceivableComparison(this, Comparison.LTE, const(n))
infix fun Perceivable<BigDecimal>.gte(n: BigDecimal) = PerceivableComparison(this, Comparison.GTE, const(n))
infix fun Perceivable<BigDecimal>.lte(n: Double) = PerceivableComparison(this, Comparison.LTE, const( BigDecimal(n) ))
infix fun Perceivable<BigDecimal>.gte(n: Double) = PerceivableComparison(this, Comparison.GTE, const( BigDecimal(n) ))
infix fun Perceivable<BigDecimal>.lte(n: Double) = PerceivableComparison(this, Comparison.LTE, const(BigDecimal(n)))
infix fun Perceivable<BigDecimal>.gte(n: Double) = PerceivableComparison(this, Comparison.GTE, const(BigDecimal(n)))
enum class Operation {
PLUS, MINUS, TIMES, DIV
@ -121,7 +117,7 @@ data class UnaryPlus<T>(val arg: Perceivable<T>) : Perceivable<T>
data class PerceivableOperation<T>(val left: Perceivable<T>, val op: Operation, val right: Perceivable<T>) : Perceivable<T>
operator fun Perceivable<BigDecimal>.plus(n: BigDecimal) = PerceivableOperation(this, Operation.PLUS, const(n))
fun<T> Perceivable<T>.plus() = UnaryPlus(this)
fun <T> Perceivable<T>.plus() = UnaryPlus(this)
operator fun Perceivable<BigDecimal>.minus(n: Perceivable<BigDecimal>) = PerceivableOperation(this, Operation.MINUS, n)
operator fun Perceivable<BigDecimal>.minus(n: BigDecimal) = PerceivableOperation(this, Operation.MINUS, const(n))
operator fun Perceivable<BigDecimal>.plus(n: Double) = PerceivableOperation(this, Operation.PLUS, const(BigDecimal(n)))
@ -139,23 +135,23 @@ class DummyPerceivable<T> : Perceivable<T>
// todo: holidays
data class Interest(val amount: Perceivable<BigDecimal>, val dayCountConvention: String,
val interest: Perceivable<BigDecimal>, val start: Perceivable<Instant>, val end: Perceivable<Instant>) : Perceivable<BigDecimal>
val interest: Perceivable<BigDecimal>, val start: Perceivable<Instant>, val end: Perceivable<Instant>) : Perceivable<BigDecimal>
fun libor(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") start: String, @Suppress("UNUSED_PARAMETER") end: String) : Perceivable<BigDecimal> = DummyPerceivable()
fun libor(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") start: Perceivable<Instant>, @Suppress("UNUSED_PARAMETER") end: Perceivable<Instant>) : Perceivable<BigDecimal> = DummyPerceivable()
fun libor(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") start: String, @Suppress("UNUSED_PARAMETER") end: String): Perceivable<BigDecimal> = DummyPerceivable()
fun libor(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") start: Perceivable<Instant>, @Suppress("UNUSED_PARAMETER") end: Perceivable<Instant>): Perceivable<BigDecimal> = DummyPerceivable()
fun interest(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") dayCountConvention: String, @Suppress("UNUSED_PARAMETER") interest: BigDecimal /* todo - appropriate type */,
@Suppress("UNUSED_PARAMETER") start: String, @Suppress("UNUSED_PARAMETER") end: String) : Perceivable<BigDecimal> = Interest(Const(amount), dayCountConvention, Const(interest), const(parseDate(start).toInstant()), const(parseDate(end).toInstant()))
@Suppress("UNUSED_PARAMETER") start: String, @Suppress("UNUSED_PARAMETER") end: String): Perceivable<BigDecimal> = Interest(Const(amount), dayCountConvention, Const(interest), const(parseDate(start).toInstant()), const(parseDate(end).toInstant()))
fun interest(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") dayCountConvention: String, @Suppress("UNUSED_PARAMETER") interest: Perceivable<BigDecimal> /* todo - appropriate type */,
@Suppress("UNUSED_PARAMETER") start: String, @Suppress("UNUSED_PARAMETER") end: String) : Perceivable<BigDecimal> =
@Suppress("UNUSED_PARAMETER") start: String, @Suppress("UNUSED_PARAMETER") end: String): Perceivable<BigDecimal> =
Interest(Const(amount), dayCountConvention, interest, const(parseDate(start).toInstant()), const(parseDate(end).toInstant()))
fun interest(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") dayCountConvention: String, @Suppress("UNUSED_PARAMETER") interest: BigDecimal /* todo - appropriate type */,
@Suppress("UNUSED_PARAMETER") start: Perceivable<Instant>, @Suppress("UNUSED_PARAMETER") end: Perceivable<Instant>) : Perceivable<BigDecimal> = Interest(const(amount), dayCountConvention, const(interest), start, end )
@Suppress("UNUSED_PARAMETER") start: Perceivable<Instant>, @Suppress("UNUSED_PARAMETER") end: Perceivable<Instant>): Perceivable<BigDecimal> = Interest(const(amount), dayCountConvention, const(interest), start, end)
fun interest(@Suppress("UNUSED_PARAMETER") amount: BigDecimal, @Suppress("UNUSED_PARAMETER") dayCountConvention: String, @Suppress("UNUSED_PARAMETER") interest: Perceivable<BigDecimal> /* todo - appropriate type */,
@Suppress("UNUSED_PARAMETER") start: Perceivable<Instant>, @Suppress("UNUSED_PARAMETER") end: Perceivable<Instant>) : Perceivable<BigDecimal> = Interest(const(amount), dayCountConvention, interest, start, end)
@Suppress("UNUSED_PARAMETER") start: Perceivable<Instant>, @Suppress("UNUSED_PARAMETER") end: Perceivable<Instant>): Perceivable<BigDecimal> = Interest(const(amount), dayCountConvention, interest, start, end)
data class Fixing(val source: String, val date: Perceivable<Instant>, val tenor: Tenor) : Perceivable<BigDecimal>

View File

@ -2,6 +2,8 @@
This is a demonstration of how to build a universal contract or higher order contracts on top of Corda. Think of the universal contract as a generalized Ricardian contract where a meta language is used as contract parameter making it possible for a single smart contract type to span a very large family of contracts.
This experimental module is maintained by Sofus Mortensen of Nordea Bank.
## Overview
### Motivation and Layers of smart contracts

View File

@ -8,16 +8,9 @@ import net.corda.core.transactions.TransactionBuilder
import java.math.BigDecimal
import java.time.Instant
/**
* Created by sofusmortensen on 23/05/16.
*/
val UNIVERSAL_PROGRAM_ID = UniversalContract()
class UniversalContract : Contract {
data class State(override val participants: List<PublicKeyTree>,
val details: Arrangement) : ContractState {
override val contract = UNIVERSAL_PROGRAM_ID
@ -75,7 +68,7 @@ class UniversalContract : Contract {
Operation.DIV -> l / r
Operation.MINUS -> l - r
Operation.PLUS -> l + r
Operation.TIMES -> l*r
Operation.TIMES -> l * r
else -> throw NotImplementedError("eval - amount - operation " + expr.op)
}
}
@ -87,7 +80,7 @@ class UniversalContract : Contract {
val a = eval(tx, expr.amount)
val i = eval(tx, expr.interest)
//todo
//TODO
a * i / 100.0.bd
}
@ -104,53 +97,53 @@ class UniversalContract : Contract {
else -> arrangement
}
// todo: think about multi layered rollouts
fun reduceRollOut(rollOut: RollOut) : Arrangement {
// TODO: think about multi layered rollouts
fun reduceRollOut(rollOut: RollOut): Arrangement {
val start = rollOut.startDate
val end = rollOut.endDate
// todo: calendar + rolling conventions
// TODO: calendar + rolling conventions
val schedule = BusinessCalendar.createGenericSchedule(start, rollOut.frequency, noOfAdditionalPeriods = 1, endDate = end)
val nextStart = schedule.first()
// todo: look into schedule for final dates
// TODO: look into schedule for final dates
val arr = replaceStartEnd(rollOut.template, start.toInstant(), nextStart.toInstant())
if (nextStart < end) {
// todo: we may have to save original start date in order to roll out correctly
// TODO: we may have to save original start date in order to roll out correctly
val newRollOut = RollOut(nextStart, end, rollOut.frequency, rollOut.template)
return replaceNext(arr, newRollOut )
}
else {
return replaceNext(arr, newRollOut)
} else {
return removeNext(arr)
}
}
fun<T> replaceStartEnd(p: Perceivable<T>, start: Instant, end: Instant) : Perceivable<T> =
@Suppress("UNCHECKED_CAST")
fun <T> replaceStartEnd(p: Perceivable<T>, start: Instant, end: Instant): Perceivable<T> =
when (p) {
is Const -> p
is TimePerceivable -> TimePerceivable( p.cmp, replaceStartEnd(p.instant, start, end) ) as Perceivable<T>
is TimePerceivable -> TimePerceivable(p.cmp, replaceStartEnd(p.instant, start, end)) as Perceivable<T>
is EndDate -> const(end) as Perceivable<T>
is StartDate -> const(start) as Perceivable<T>
is UnaryPlus -> UnaryPlus( replaceStartEnd(p.arg, start, end) )
is PerceivableOperation -> PerceivableOperation<T>( 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<T>
is Fixing -> Fixing( p.source, replaceStartEnd(p.date, start, end), p.tenor) as Perceivable<T>
is UnaryPlus -> UnaryPlus(replaceStartEnd(p.arg, start, end))
is PerceivableOperation -> PerceivableOperation<T>(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<T>
is Fixing -> Fixing(p.source, replaceStartEnd(p.date, start, end), p.tenor) as Perceivable<T>
else -> throw NotImplementedError("replaceStartEnd " + p.javaClass.name)
}
fun replaceStartEnd(arrangement: Arrangement, start: Instant, end: Instant) : Arrangement =
fun replaceStartEnd(arrangement: Arrangement, start: Instant, end: Instant): Arrangement =
when (arrangement) {
is And -> And(arrangement.arrangements.map { replaceStartEnd(it, start, end) }.toSet())
is Zero -> arrangement
is Transfer -> Transfer( 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 Transfer -> Transfer(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 Continuation -> arrangement
else -> throw NotImplementedError("replaceStartEnd " + arrangement.javaClass.name)
}
fun replaceNext(arrangement: Arrangement, nextReplacement: RollOut) : Arrangement =
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 And -> And(arrangement.arrangements.map { replaceNext(it, nextReplacement) }.toSet())
@ -160,7 +153,7 @@ class UniversalContract : Contract {
else -> throw NotImplementedError("replaceNext " + arrangement.javaClass.name)
}
fun removeNext(arrangement: Arrangement) : Arrangement =
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 And -> {
@ -199,7 +192,7 @@ class UniversalContract : Contract {
val action = actions[value.name] ?: throw IllegalArgumentException("Failed requirement: action must be defined")
// todo: not sure this is necessary??
// TODO: not sure this is necessary??
val rest = extractRemainder(arr, action)
// for now - let's assume not
@ -264,8 +257,6 @@ class UniversalContract : Contract {
val expectedArr = replaceFixing(tx, arr,
value.fixes.associateBy({ it.of }, { it.value }), unusedFixes)
// debugCompare(expectedArr, outState.details)
requireThat {
"relevant fixing must be included" by unusedFixes.isEmpty()
"output state does not reflect fix command" by
@ -276,6 +267,7 @@ class UniversalContract : Contract {
}
}
@Suppress("UNCHECKED_CAST")
fun <T> replaceFixing(tx: TransactionForContract, perceivable: Perceivable<T>,
fixings: Map<FixOf, BigDecimal>, unusedFixings: MutableSet<FixOf>): Perceivable<T> =
when (perceivable) {
@ -307,7 +299,7 @@ class UniversalContract : Contract {
is Zero -> arr
is And -> And(arr.arrangements.map { replaceFixing(tx, it, fixings, unusedFixings) }.toSet())
is Transfer -> Transfer(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, it.actors, 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)

View File

@ -8,10 +8,6 @@ import net.corda.core.crypto.PublicKeyTree
import java.time.Instant
import java.time.LocalDate
/**
* Created by sofusmortensen on 23/05/16.
*/
fun Instant.toLocalDate(): LocalDate = LocalDate.ofEpochDay(this.epochSecond / 60 / 60 / 24)
fun LocalDate.toInstant(): Instant = Instant.ofEpochSecond(this.toEpochDay() * 60 * 60 * 24)
@ -35,7 +31,7 @@ private fun liablePartiesVisitor(action: Action): ImmutableSet<PublicKeyTree> =
else
Sets.difference(liablePartiesVisitor(action.arrangement), ImmutableSet.of(action.actors.single())).immutableCopy()
/** returns list of potentially liable parties for a given contract */
/** Returns list of potentially liable parties for a given contract */
fun liableParties(contract: Arrangement): Set<PublicKeyTree> = liablePartiesVisitor(contract)
private fun involvedPartiesVisitor(action: Action): Set<PublicKeyTree> =
@ -71,14 +67,14 @@ fun replaceParty(arrangement: Arrangement, from: Party, to: Party): Arrangement
else -> throw IllegalArgumentException()
}
fun extractRemainder(arrangement: Arrangement, action: Action) : Arrangement = when (arrangement) {
fun extractRemainder(arrangement: Arrangement, action: Action): Arrangement = when (arrangement) {
is Actions -> if (arrangement.actions.contains(action)) zero else arrangement
is And -> {
val a = arrangement.arrangements.map { extractRemainder(it, action) }.filter { it != zero }
when (a.size) {
0 -> zero
1 -> a.single()
else -> And( a.toSet() )
else -> And(a.toSet())
}
}
else -> arrangement
@ -100,11 +96,11 @@ fun actions(arrangement: Arrangement): Map<String, Action> = when (arrangement)
}
fun debugCompare(left: String, right: String) {
assert(left.equals(right))
assert(left == right)
}
fun<T> debugCompare(perLeft: Perceivable<T>, perRight: Perceivable<T>) {
if (perLeft.equals(perRight)) return
fun <T> debugCompare(perLeft: Perceivable<T>, perRight: Perceivable<T>) {
if (perLeft == perRight) return
when (perLeft) {
is UnaryPlus -> {
@ -117,7 +113,7 @@ fun<T> debugCompare(perLeft: Perceivable<T>, perRight: Perceivable<T>) {
if (perRight is PerceivableOperation) {
debugCompare(perLeft.left, perRight.left)
debugCompare(perLeft.right, perRight.right)
assert( perLeft.op.equals(perRight.op) )
assert(perLeft.op == perRight.op)
return
}
}
@ -127,7 +123,7 @@ fun<T> debugCompare(perLeft: Perceivable<T>, perRight: Perceivable<T>) {
debugCompare(perLeft.interest, perRight.interest)
debugCompare(perLeft.start, perRight.start)
debugCompare(perLeft.end, perRight.end)
assert(perLeft.dayCountConvention.equals(perRight.dayCountConvention))
assert(perLeft.dayCountConvention == perRight.dayCountConvention)
return
}
}
@ -145,23 +141,25 @@ fun<T> debugCompare(perLeft: Perceivable<T>, perRight: Perceivable<T>) {
}
fun debugCompare(parLeft: Party, parRight: Party) {
assert( parLeft.equals(parRight) )
assert(parLeft == parRight)
}
fun debugCompare(left: Frequency, right: Frequency) {
assert( left.equals(right) )
assert(left == right)
}
fun debugCompare(left: LocalDate, right: LocalDate) {
assert( left.equals(right) )
assert(left == right)
}
fun debugCompare(parLeft: Set<Party>, parRight: Set<Party>) {
if (parLeft.equals(parRight)) return
if (parLeft == parRight) return
assert( parLeft.equals(parRight) )
assert(parLeft == parRight)
}
fun debugCompare(arrLeft: Arrangement, arrRight: Arrangement) {
if (arrLeft.equals(arrRight)) return
if (arrLeft == arrRight) return
when (arrLeft) {
is Transfer -> {
@ -175,7 +173,7 @@ fun debugCompare(arrLeft: Arrangement, arrRight: Arrangement) {
}
is And -> {
if (arrRight is And) {
arrLeft.arrangements.zip( arrRight.arrangements).forEach {
arrLeft.arrangements.zip(arrRight.arrangements).forEach {
debugCompare(it.first, it.second)
}
return
@ -183,7 +181,7 @@ fun debugCompare(arrLeft: Arrangement, arrRight: Arrangement) {
}
is Actions -> {
if (arrRight is Actions) {
arrLeft.actions.zip( arrRight.actions ).forEach {
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)
@ -203,5 +201,5 @@ fun debugCompare(arrLeft: Arrangement, arrRight: Arrangement) {
}
}
assert( false)
assert(false)
}

View File

@ -10,10 +10,6 @@ import org.junit.Test
import java.time.Instant
import java.time.LocalDate
/**
* Created by sofusmortensen on 05/09/16.
*/
class Cap {
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
@ -135,13 +131,13 @@ class Cap {
val stateInitial = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractInitial)
val stateAfterFixingFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterFixingFirst)
val stateAfterFixingFirst = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractAfterFixingFirst)
val stateAfterExecutionFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterExecutionFirst)
val statePaymentFirst = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), paymentFirst)
val stateAfterExecutionFirst = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractAfterExecutionFirst)
val statePaymentFirst = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), paymentFirst)
val stateAfterFixingFinal = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractAfterFixingFinal)
val statePaymentFinal = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), paymentFinal)
val stateAfterFixingFinal = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractAfterFixingFinal)
val statePaymentFinal = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), paymentFinal)
val contractLimitedCap = arrange {
rollOut("2016-04-01".ld, "2017-04-01".ld, Frequency.SemiAnnual, object {

View File

@ -8,10 +8,6 @@ import org.junit.Test
import java.time.Instant
import java.time.LocalDate
/**
* Created by sofusmortensen on 25/08/16.
*/
class Caplet {
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
@ -47,11 +43,11 @@ class Caplet {
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)
val stateFixed = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractFixed)
val stateFixed = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractFixed)
val stateFinal = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractFinal )
val stateFinal = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractFinal)
@Test
fun issue() {

View File

@ -5,10 +5,6 @@ import net.corda.core.crypto.generateKeyPair
import org.junit.Test
import java.util.*
/**
* Created by sofusmortensen on 08/06/16.
*/
// Test parties
val acmeCorp = Party("ACME Corporation", generateKeyPair().public)
val highStreetBank = Party("High Street Bank", generateKeyPair().public)
@ -83,29 +79,29 @@ class ContractDefinition {
}
/* @Test
fun `builder problem - should not compile`() {
val arr = arrange {
actions {
acmeCorp.may {
"execute".anytime {
acmeCorp.may {
"problem".anytime {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
}
}
}
}
/* @Test
fun `builder problem - should not compile`() {
val arr = arrange {
actions {
acmeCorp.may {
"execute".anytime {
acmeCorp.may {
"problem".anytime {
highStreetBank.gives(acmeCorp, 1.M, USD)
}
}
}
}
}
}
assert( arr is Actions )
assert( arr is Actions )
if (arr is Actions) {
assert( arr.actions.size == 1)
}
}
*/
if (arr is Actions) {
assert( arr.actions.size == 1)
}
}
*/
@Test
fun `builder problem - legal`() {
val arr = arrange {
@ -124,10 +120,10 @@ class ContractDefinition {
}
}
assert( arr is Actions )
assert(arr is Actions)
if (arr is Actions) {
assert( arr.actions.size == 1)
assert(arr.actions.size == 1)
}
}

View File

@ -1,14 +1,10 @@
package net.corda.contracts.universal
import net.corda.testing.*
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.testing.transaction
import org.junit.Test
import java.time.Instant
/**
* Created by sofusmortensen on 01/06/16.
*/
class FXSwap {
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
@ -28,18 +24,18 @@ class FXSwap {
val transfer1 = arrange { highStreetBank.gives(acmeCorp, 1200.K, USD) }
val transfer2 = arrange { acmeCorp.gives(highStreetBank, 1.M, EUR) }
val outState1 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transfer1 )
val outState2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transfer2 )
val outState1 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transfer1)
val outState2 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transfer2)
val transferBad1 = arrange { highStreetBank.gives(acmeCorp, 1200.K, GBP) } // wrong currency
val transferBad2 = arrange { acmeCorp.gives(highStreetBank, 900.K, EUR) } // wrong amount
val transferBad3 = arrange { highStreetBank.gives(highStreetBank, 1.M, EUR) } // wrong party
val outStateBad1 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferBad1 )
val outStateBad2 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferBad2 )
val outStateBad3 = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferBad3 )
val outStateBad1 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transferBad1)
val outStateBad2 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transferBad2)
val outStateBad3 = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transferBad3)
val inState = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contract)
val inState = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contract)
@Test
fun `issue - signature`() {

View File

@ -8,10 +8,6 @@ import org.junit.Test
import java.time.Instant
import java.time.LocalDate
/**
* Created by sofusmortensen on 12/09/16.
*/
class IRS {
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
@ -42,7 +38,7 @@ class IRS {
}
val stateStart = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contract)
val stateStart = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contract)
@Test
fun issue() {

View File

@ -8,10 +8,6 @@ import org.junit.Test
import java.time.Instant
import kotlin.test.assertEquals
/**
* Created by sofusmortensen on 08/09/16.
*/
class RollOutTests {
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
@ -129,14 +125,17 @@ class RollOutTests {
fun `arrangement equality transfer`() {
assertEquals(contract_transfer1, contract_transfer2)
}
@Test
fun `arrangement equality action`() {
assertEquals(contract_action1, contract_action2)
}
@Test
fun `arrangement equality and`() {
assertEquals(contract_and1, contract_and2)
}
@Test
fun `arrangement equality complex`() {
assertEquals(contract, contract2)
@ -174,10 +173,10 @@ class RollOutTests {
output { stateStep1b }
timestamp(TEST_TX_TIME_1)
/* tweak {
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
this `fails with` "action must be defined"
}*/
/* tweak {
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
this `fails with` "action must be defined"
}*/
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("transfer") }

View File

@ -1,17 +1,8 @@
package net.corda.contracts.universal
import net.corda.core.contracts.Frequency
import java.math.BigDecimal
/**
* Created by sofusmortensen on 28/06/16.
*/
// Swaption
class Swaption {
val notional = 10.M
val currency = USD
val coupon = 1.5.bd

View File

@ -1,14 +1,10 @@
package net.corda.contracts.universal
import net.corda.testing.*
import net.corda.core.utilities.DUMMY_NOTARY
import net.corda.testing.transaction
import org.junit.Test
import java.time.Instant
/**
* Created by sofusmortensen on 01/06/16.
*/
class ZeroCouponBond {
val contract = arrange {
@ -36,16 +32,16 @@ class ZeroCouponBond {
val transfer = arrange { highStreetBank.gives(acmeCorp, 100.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)
val outState = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transfer )
val outStateWrong = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), transferWrong )
val outState = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transfer)
val outStateWrong = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), transferWrong)
val outStateMove = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractMove )
val outStateMove = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractMove)
@Test
fun basic() {
assert( Zero().equals(Zero()))
assert(Zero().equals(Zero()))
}
@ -131,7 +127,7 @@ class ZeroCouponBond {
this `fails with` "output state does not reflect move command"
}
output { outStateMove}
output { outStateMove }
command(acmeCorp.owningKey, momAndPop.owningKey, highStreetBank.owningKey) {
UniversalContract.Commands.Move(acmeCorp, momAndPop)

View File

@ -2,10 +2,6 @@ package net.corda.contracts.universal
import net.corda.core.contracts.USD
/**
* Created by sofusmortensen on 23/05/16.
*/
// various example arrangements using basic syntax
val cds_contract = arrange {