mirror of
https://github.com/corda/corda.git
synced 2025-01-29 15:43:55 +00:00
Universal: checkpoint before refactor
This commit is contained in:
parent
dab883dcba
commit
b93aa71afa
@ -4,6 +4,7 @@ import com.r3corda.core.contracts.Amount
|
||||
import com.r3corda.core.contracts.Frequency
|
||||
import com.r3corda.core.crypto.Party
|
||||
import java.math.BigDecimal
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -49,7 +50,7 @@ data class Or(val actions: Set<Action>) : Arrangement
|
||||
|
||||
|
||||
// Roll out of arrangement
|
||||
data class RollOut(val startDate: String, val endDate: String, val frequency: Frequency, val template: Arrangement) : Arrangement
|
||||
data class RollOut(val startDate: LocalDate, val endDate: LocalDate, val frequency: Frequency, val template: Arrangement) : Arrangement
|
||||
|
||||
|
||||
// Continuation of roll out
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.r3corda.contracts.universal
|
||||
|
||||
import com.r3corda.core.contracts.BusinessCalendar
|
||||
import com.r3corda.core.contracts.Tenor
|
||||
import java.math.BigDecimal
|
||||
import java.time.Instant
|
||||
@ -44,14 +45,16 @@ class EndDate : Perceivable<Instant>
|
||||
*/
|
||||
data class TimePerceivable(val cmp: Comparison, val instant: Perceivable<Instant>) : Perceivable<Boolean>
|
||||
|
||||
fun parseDate(str: String) = Instant.parse(str+"T00:00:00Z")!!
|
||||
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))
|
||||
fun after(expiry: Instant) = TimePerceivable(Comparison.GTE, const(expiry))
|
||||
fun before(expiry: String) = TimePerceivable(Comparison.LTE, const(parseDate(expiry)))
|
||||
fun after(expiry: String) = TimePerceivable(Comparison.GTE, const(parseDate(expiry)))
|
||||
fun before(expiry: String) = TimePerceivable(Comparison.LTE, const(parseDate(expiry).toInstant()))
|
||||
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)
|
||||
@ -102,23 +105,23 @@ class DummyPerceivable<T> : Perceivable<T>
|
||||
|
||||
// todo: holidays
|
||||
data class Interest(val amount: Perceivable<BigDecimal>, val dayCountConvention: String,
|
||||
val interest: Perceivable<BigDecimal>, val start: LocalDate, val end: LocalDate) : 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 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), parseDate(start).toLocalDate(), parseDate(end).toLocalDate())
|
||||
@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> =
|
||||
Interest(Const(amount), dayCountConvention, interest, parseDate(start).toLocalDate(), parseDate(end).toLocalDate())
|
||||
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> = DummyPerceivable()
|
||||
|
||||
fun interest(@Suppress("UNUSED_PARAMETER") rate: 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> = DummyPerceivable()
|
||||
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)
|
||||
|
||||
class Fixing(val source: String, val date: Perceivable<Instant>, val tenor: Tenor) : Perceivable<BigDecimal>
|
||||
|
||||
|
@ -4,6 +4,7 @@ import com.r3corda.core.contracts.*
|
||||
import com.r3corda.core.crypto.Party
|
||||
import com.r3corda.core.crypto.SecureHash
|
||||
import com.r3corda.core.transactions.TransactionBuilder
|
||||
import com.sun.tools.corba.se.idl.InvalidArgument
|
||||
import java.math.BigDecimal
|
||||
import java.security.PublicKey
|
||||
import java.time.Instant
|
||||
@ -39,19 +40,11 @@ class UniversalContract : Contract {
|
||||
class Issue : TypeOnlyCommandData(), Commands
|
||||
}
|
||||
|
||||
fun <T> eval(@Suppress("UNUSED_PARAMETER") tx: TransactionForContract, expr: Perceivable<T>): T = when (expr) {
|
||||
is Const -> expr.value
|
||||
else -> throw Error("Unable to evaluate")
|
||||
}
|
||||
|
||||
fun eval(@Suppress("UNUSED_PARAMETER") tx: TransactionForContract, expr: Perceivable<LocalDate>): LocalDate = when (expr) {
|
||||
is Const -> expr.value
|
||||
else -> throw Error("Unable to evaluate")
|
||||
}
|
||||
fun eval(@Suppress("UNUSED_PARAMETER") tx: TransactionForContract, expr: Perceivable<Instant>): Instant = when (expr) {
|
||||
is Const -> expr.value
|
||||
else -> throw Error("Unable to evaluate")
|
||||
}
|
||||
|
||||
fun eval(tx: TransactionForContract, expr: Perceivable<Boolean>): Boolean = when (expr) {
|
||||
is PerceivableAnd -> eval(tx, expr.left) && eval(tx, expr.right)
|
||||
is PerceivableOr -> eval(tx, expr.right) || eval(tx, expr.right)
|
||||
@ -64,7 +57,6 @@ class UniversalContract : Contract {
|
||||
else -> throw NotImplementedError("eval - Boolean - " + expr.javaClass.name)
|
||||
}
|
||||
|
||||
|
||||
fun eval(tx: TransactionForContract, expr: Perceivable<BigDecimal>): BigDecimal =
|
||||
when (expr) {
|
||||
is Const<BigDecimal> -> expr.value
|
||||
@ -102,41 +94,6 @@ class UniversalContract : Contract {
|
||||
else -> throw NotImplementedError("eval - BigDecimal - " + expr.javaClass.name)
|
||||
}
|
||||
|
||||
fun reduce(tx: TransactionForContract, expr: Perceivable<BigDecimal>): Perceivable<BigDecimal> = when (expr) {
|
||||
is PerceivableOperation -> {
|
||||
val left = reduce(tx, expr.left)
|
||||
val right = reduce(tx, expr.right)
|
||||
if (left is Const && right is Const)
|
||||
when (expr.op) {
|
||||
//Operation.DIV -> Const( left.value / right.value )
|
||||
Operation.MINUS -> Const(left.value - right.value)
|
||||
Operation.PLUS -> Const(left.value + right.value)
|
||||
//Operation.TIMES -> Const( left.value * right.value )
|
||||
else -> throw NotImplementedError("reduce - " + expr.op.name)
|
||||
}
|
||||
else
|
||||
PerceivableOperation(left, expr.op, right)
|
||||
}
|
||||
is UnaryPlus -> {
|
||||
val amount = reduce(tx, expr.arg)
|
||||
if (amount is Const) {
|
||||
if (amount.value > BigDecimal.ZERO)
|
||||
amount
|
||||
else
|
||||
Const(BigDecimal.ZERO)
|
||||
} else
|
||||
UnaryPlus(amount)
|
||||
}
|
||||
is Interest -> Interest(reduce(tx, expr.amount), expr.dayCountConvention, reduce(tx, expr.interest), expr.start, expr.end)
|
||||
else -> expr
|
||||
}
|
||||
|
||||
fun checkAndReduce(tx: TransactionForContract, arrangement: Arrangement): Arrangement = when (arrangement) {
|
||||
is Transfer -> Transfer(reduce(tx, arrangement.amount), arrangement.currency, arrangement.from, arrangement.to)
|
||||
is And -> And(arrangement.arrangements.map { checkAndReduce(tx, it) }.toSet())
|
||||
else -> arrangement
|
||||
}
|
||||
|
||||
fun validateImmediateTransfers(tx: TransactionForContract, arrangement: Arrangement): Arrangement = when (arrangement) {
|
||||
is Transfer -> {
|
||||
val amount = eval(tx, arrangement.amount)
|
||||
@ -147,6 +104,32 @@ class UniversalContract : Contract {
|
||||
else -> arrangement
|
||||
}
|
||||
|
||||
// todo: think about multi layered rollouts
|
||||
fun reduceRollOut(rollOut: RollOut) : Arrangement {
|
||||
val start = rollOut.startDate
|
||||
val end = rollOut.endDate
|
||||
|
||||
// todo: calendar + rolling conventions
|
||||
val schedule = BusinessCalendar.createGenericSchedule(start, rollOut.frequency, noOfAdditionalPeriods = 1, endDate = end)
|
||||
|
||||
val next = schedule.first() // fail if no dates
|
||||
|
||||
val newRollOut = RollOut(next, end, rollOut.frequency, rollOut.template)
|
||||
|
||||
return replaceNext(rollOut.template, newRollOut )
|
||||
}
|
||||
|
||||
fun replaceNext(arrangement: Arrangement, nextReplacement: RollOut) : Arrangement {
|
||||
return when (arrangement) {
|
||||
is Or -> Or(arrangement.actions.map { replaceNext(it, nextReplacement)!! as Action }.toSet())
|
||||
is And -> And(arrangement.arrangements.map { replaceNext(it, nextReplacement) }.toSet())
|
||||
is Action -> Action( arrangement.name, arrangement.condition, arrangement.actors, replaceNext(arrangement.arrangement, nextReplacement))
|
||||
is Transfer -> arrangement
|
||||
is Zero -> arrangement
|
||||
else -> throw NotImplementedError("replaceNext " + arrangement.javaClass.name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun verify(tx: TransactionForContract) {
|
||||
|
||||
requireThat {
|
||||
@ -160,7 +143,14 @@ class UniversalContract : Contract {
|
||||
when (value) {
|
||||
is Commands.Action -> {
|
||||
val inState = tx.inputs.single() as State
|
||||
val actions = actions(inState.details)
|
||||
val arr = when (inState.details) {
|
||||
is Or -> inState.details
|
||||
is Action -> inState.details
|
||||
is RollOut -> reduceRollOut(inState.details)
|
||||
else -> throw InvalidArgument("Unexpected arrangement, " + tx.inputs.single())
|
||||
}
|
||||
|
||||
val actions = actions(arr)
|
||||
|
||||
val action = actions[value.name] ?: throw IllegalArgumentException("Failed requirement: action must be defined")
|
||||
|
||||
@ -229,8 +219,8 @@ class UniversalContract : Contract {
|
||||
}
|
||||
|
||||
fun <T> replaceFixing(tx: TransactionForContract, perceivable: Perceivable<T>,
|
||||
fixings: Map<FixOf, BigDecimal>, unusedFixings: MutableSet<FixOf>): Perceivable<T> =
|
||||
when (perceivable) {
|
||||
fixings: Map<FixOf, BigDecimal>, unusedFixings: MutableSet<FixOf>): Perceivable<T> {
|
||||
return when (perceivable) {
|
||||
is Const -> perceivable
|
||||
is UnaryPlus -> UnaryPlus(replaceFixing(tx, perceivable.arg, fixings, unusedFixings))
|
||||
is PerceivableOperation -> PerceivableOperation(replaceFixing(tx, perceivable.left, fixings, unusedFixings),
|
||||
@ -244,6 +234,7 @@ class UniversalContract : Contract {
|
||||
} else perceivable
|
||||
else -> throw NotImplementedError("replaceFixing - " + perceivable.javaClass.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun replaceFixing(tx: TransactionForContract, arr: Action,
|
||||
fixings: Map<FixOf, BigDecimal>, unusedFixings: MutableSet<FixOf>) =
|
||||
@ -256,6 +247,7 @@ class UniversalContract : Contract {
|
||||
is Zero -> arr
|
||||
is Transfer -> Transfer(replaceFixing(tx, arr.amount, fixings, unusedFixings), arr.currency, arr.from, arr.to)
|
||||
is Or -> Or(arr.actions.map { replaceFixing(tx, it, fixings, unusedFixings) }.toSet())
|
||||
is RollOut -> RollOut(arr.startDate, arr.endDate, arr.frequency, replaceFixing(tx, arr.template, fixings, unusedFixings))
|
||||
else -> throw NotImplementedError("replaceFixing - " + arr.javaClass.name)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
package com.r3corda.contracts.universal
|
||||
|
||||
import com.r3corda.core.contracts.BusinessCalendar
|
||||
import com.r3corda.core.contracts.Frequency
|
||||
import com.r3corda.core.crypto.Party
|
||||
import java.math.BigDecimal
|
||||
import java.time.LocalDate
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -23,19 +25,19 @@ val zero = Zero()
|
||||
open class ContractBuilder {
|
||||
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(const(amount), currency, this, beneficiary)
|
||||
contracts.add( c )
|
||||
contracts.add(c)
|
||||
return c
|
||||
}
|
||||
|
||||
fun Party.gives(beneficiary: Party, amount: Perceivable<BigDecimal>, currency: Currency) : Transfer {
|
||||
fun Party.gives(beneficiary: Party, amount: Perceivable<BigDecimal>, currency: Currency): Transfer {
|
||||
val c = Transfer(amount, currency, this, beneficiary)
|
||||
contracts.add( c )
|
||||
contracts.add(c)
|
||||
return c
|
||||
}
|
||||
|
||||
fun Party.may(init: ActionBuilder.() -> Unit) : Or {
|
||||
fun Party.may(init: ActionBuilder.() -> Unit): Or {
|
||||
val b = ActionBuilder(setOf(this))
|
||||
b.init()
|
||||
val c = Or(b.actions.toSet())
|
||||
@ -43,7 +45,7 @@ open class ContractBuilder {
|
||||
return c
|
||||
}
|
||||
|
||||
fun Set<Party>.may(init: ActionBuilder.() -> Unit) : Or {
|
||||
fun Set<Party>.may(init: ActionBuilder.() -> Unit): Or {
|
||||
val b = ActionBuilder(this)
|
||||
b.init()
|
||||
val c = Or(b.actions.toSet())
|
||||
@ -51,32 +53,48 @@ open class ContractBuilder {
|
||||
return c
|
||||
}
|
||||
|
||||
|
||||
infix fun Or.or(ors: Or): Or {
|
||||
assert(ors.actions.size == 1)
|
||||
assert(contracts[contracts.lastIndex-1] == this)
|
||||
assert(contracts[contracts.lastIndex] == ors)
|
||||
contracts.removeAt(contracts.lastIndex)
|
||||
|
||||
val c = Or(this.actions + ors.actions.single())
|
||||
contracts[contracts.lastIndex] = c
|
||||
return c
|
||||
}
|
||||
|
||||
infix fun Party.or(party: Party) = setOf(this, party)
|
||||
infix fun Set<Party>.or(party: Party) = this.plus(party)
|
||||
|
||||
@Deprecated(level = DeprecationLevel.ERROR, message = "Not allowed")
|
||||
fun Action(@Suppress("UNUSED_PARAMETER") name: String, @Suppress("UNUSED_PARAMETER") condition: Perceivable<Boolean>,
|
||||
@Suppress("UNUSED_PARAMETER") actors: Set<Party>, @Suppress("UNUSED_PARAMETER") arrangement: Arrangement) {}
|
||||
@Suppress("UNUSED_PARAMETER") actors: Set<Party>, @Suppress("UNUSED_PARAMETER") arrangement: Arrangement) {
|
||||
}
|
||||
|
||||
@Deprecated(level = DeprecationLevel.ERROR, message = "Not available")
|
||||
fun<T> String.anytime(@Suppress("UNUSED_PARAMETER") ignore: T ) {}
|
||||
fun <T> String.anytime(@Suppress("UNUSED_PARAMETER") ignore: T) {
|
||||
}
|
||||
|
||||
@Deprecated(level = DeprecationLevel.ERROR, message = "Not available")
|
||||
fun<T> String.givenThat(@Suppress("UNUSED_PARAMETER") ignore: T ) {}
|
||||
fun <T> String.givenThat(@Suppress("UNUSED_PARAMETER") ignore: T) {
|
||||
}
|
||||
|
||||
@Deprecated(level = DeprecationLevel.ERROR, message = "Not available")
|
||||
fun<T> String.givenThat(@Suppress("UNUSED_PARAMETER") ignore1: T, @Suppress("UNUSED_PARAMETER") ignore2: T ) {}
|
||||
fun <T> String.givenThat(@Suppress("UNUSED_PARAMETER") ignore1: T, @Suppress("UNUSED_PARAMETER") ignore2: T) {
|
||||
}
|
||||
|
||||
/* fun Party.gives(beneficiary: Party, amount: Perceivable<Long>, currency: Currency) {
|
||||
contracts.add( Transfer(amount, currency, this, beneficiary))
|
||||
}*/
|
||||
/* 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) )
|
||||
infix fun Action.or(arrangement: Action) = Or( setOf(this, arrangement) )
|
||||
infix fun Or.or(arrangement: Action) = Or( this.actions.plusElement(arrangement) )
|
||||
infix fun Or.or(ors: Or) = Or( this.actions.plus(ors.actions) )
|
||||
infix fun Arrangement.and(arrangement: Arrangement) = And(setOf(this, arrangement))
|
||||
infix fun Action.or(arrangement: Action) = Or(setOf(this, arrangement))
|
||||
// infix fun Or.or(arrangement: Action) = Or( this.actions.plusElement(arrangement) )
|
||||
// infix fun Or.or(ors: Or) = Or( this.actions.plus(ors.actions) )
|
||||
|
||||
fun rollOut(startDate: String, endDate: String, frequency: Frequency, init: RollOutBuilder<Dummy>.() -> Unit) : RollOut {
|
||||
fun rollOut(startDate: LocalDate, endDate: LocalDate, frequency: Frequency, init: RollOutBuilder<Dummy>.() -> Unit): RollOut {
|
||||
val b = RollOutBuilder(startDate, endDate, frequency, Dummy())
|
||||
b.init()
|
||||
val c = b.final()
|
||||
@ -84,7 +102,7 @@ open class ContractBuilder {
|
||||
return c
|
||||
}
|
||||
|
||||
fun <T> rollOut(startDate: String, endDate: String, frequency: Frequency, vars: T, init: RollOutBuilder<T>.() -> Unit) : RollOut {
|
||||
fun <T> rollOut(startDate: LocalDate, endDate: LocalDate, frequency: Frequency, vars: T, init: RollOutBuilder<T>.() -> Unit): RollOut {
|
||||
val b = RollOutBuilder(startDate, endDate, frequency, vars)
|
||||
b.init()
|
||||
val c = b.final()
|
||||
@ -92,6 +110,8 @@ open class ContractBuilder {
|
||||
return c
|
||||
}
|
||||
|
||||
val String.ld: LocalDate get() = BusinessCalendar.parseDateFromString(this)
|
||||
|
||||
open fun final() =
|
||||
when (contracts.size) {
|
||||
0 -> zero
|
||||
@ -100,6 +120,7 @@ open class ContractBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
interface GivenThatResolve {
|
||||
fun resolve(contract: Arrangement)
|
||||
}
|
||||
@ -139,7 +160,7 @@ data class Parameter<T>(val initialValue: T) : Perceivable<T>
|
||||
|
||||
fun<T> variable(v: T) = Parameter<T>(v)
|
||||
|
||||
class RollOutBuilder<T>(val startDate: String, val endDate: String, val frequency: Frequency, val vars: T) : ContractBuilder() {
|
||||
class RollOutBuilder<T>(val startDate: LocalDate, val endDate: LocalDate, val frequency: Frequency, val vars: T) : ContractBuilder() {
|
||||
|
||||
val start = StartDate()
|
||||
val end = EndDate()
|
||||
|
@ -1,11 +1,13 @@
|
||||
package com.r3corda.contracts.universal
|
||||
|
||||
import com.r3corda.core.contracts.FixOf
|
||||
import com.r3corda.core.contracts.Frequency
|
||||
import com.r3corda.core.contracts.Tenor
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.testing.transaction
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
import java.time.LocalDate
|
||||
|
||||
/**
|
||||
* Created by sofusmortensen on 05/09/16.
|
||||
@ -18,16 +20,19 @@ class Cap {
|
||||
val notional = 50.M
|
||||
val currency = EUR
|
||||
|
||||
val tradeDate: LocalDate = LocalDate.of(2016, 9, 1)
|
||||
|
||||
val contract = arrange {
|
||||
rollOut("2016-04-01", "2017-04-01", Frequency.Quarterly) {
|
||||
rollOut("2016-09-01".ld, "2017-04-01".ld, Frequency.Quarterly) {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
"exercise".anytime {
|
||||
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("6M")), start, end)
|
||||
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
|
||||
highStreetBank.gives(acmeCorp, floating - fixed, currency)
|
||||
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
|
||||
next()
|
||||
}
|
||||
} or acmeCorp.may {
|
||||
} or
|
||||
acmeCorp.may {
|
||||
"skip".anytime {
|
||||
next()
|
||||
}
|
||||
@ -35,11 +40,53 @@ class Cap {
|
||||
}
|
||||
}
|
||||
|
||||
val contractFixed = arrange {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
"exercise".anytime() {
|
||||
val floating1 = interest(notional, "act/365", 1.0.bd, "2016-04-01", "2016-07-01")
|
||||
val fixed1 = interest(notional, "act/365", 0.5.bd, "2016-04-01", "2016-07-01")
|
||||
highStreetBank.gives(acmeCorp, (floating1 - fixed1).plus(), currency)
|
||||
rollOut("2016-07-01".ld, "2017-04-01".ld, Frequency.Quarterly) {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
"exercise".anytime {
|
||||
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("6M")), start, end)
|
||||
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
|
||||
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
|
||||
next()
|
||||
}
|
||||
} or acmeCorp.may {
|
||||
"skip".anytime {
|
||||
next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} or acmeCorp.may {
|
||||
"skip".anytime {
|
||||
rollOut("2016-07-01".ld, "2017-04-01".ld, Frequency.Quarterly) {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
"exercise".anytime {
|
||||
val floating = interest(notional, "act/365", fix("LIBOR", start, Tenor("6M")), start, end)
|
||||
val fixed = interest(notional, "act/365", 0.5.bd, start, end)
|
||||
highStreetBank.gives(acmeCorp, (floating - fixed).plus(), currency)
|
||||
next()
|
||||
}
|
||||
} or acmeCorp.may {
|
||||
"skip".anytime {
|
||||
next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val stateStart = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contract)
|
||||
|
||||
val stateFixed = UniversalContract.State( listOf(DUMMY_NOTARY.owningKey), contractFixed)
|
||||
|
||||
val contractTARN = arrange {
|
||||
rollOut("2016-04-01", "2017-04-01", Frequency.Quarterly, object {
|
||||
rollOut("2016-04-01".ld, "2017-04-01".ld, Frequency.Quarterly, object {
|
||||
val limit = variable(150.K)
|
||||
}) {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
@ -77,4 +124,49 @@ class Cap {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fixing`() {
|
||||
transaction {
|
||||
input { stateStart }
|
||||
output { stateFixed }
|
||||
timestamp(TEST_TX_TIME_1)
|
||||
|
||||
tweak {
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
||||
this `fails with` "action must be defined"
|
||||
}
|
||||
|
||||
tweak {
|
||||
// wrong source
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBORx", tradeDate, Tenor("6M")), 1.0.bd))) }
|
||||
|
||||
this `fails with` "relevant fixing must be included"
|
||||
}
|
||||
|
||||
tweak {
|
||||
// wrong date
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", tradeDate.plusYears(1), Tenor("6M")), 1.0.bd))) }
|
||||
|
||||
this `fails with` "relevant fixing must be included"
|
||||
}
|
||||
|
||||
tweak {
|
||||
// wrong tenor
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", tradeDate, Tenor("3M")), 1.0.bd))) }
|
||||
|
||||
this `fails with` "relevant fixing must be included"
|
||||
}
|
||||
|
||||
tweak {
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", tradeDate, Tenor("6M")), 1.5.bd))) }
|
||||
|
||||
this `fails with` "output state does not reflect fix command"
|
||||
}
|
||||
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Fix(listOf(com.r3corda.core.contracts.Fix(FixOf("LIBOR", tradeDate, Tenor("6M")), 1.0.bd))) }
|
||||
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ class Caplet {
|
||||
|
||||
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
|
||||
|
||||
val dt: LocalDate = LocalDate.of(2016, 9, 1)
|
||||
val tradeDate: LocalDate = LocalDate.of(2016, 9, 1)
|
||||
|
||||
val notional = 50.M
|
||||
val currency = EUR
|
||||
@ -26,7 +26,7 @@ class Caplet {
|
||||
val contract = arrange {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
"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", 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.gives(acmeCorp, (floating - fixed).plus(), currency)
|
||||
}
|
||||
@ -102,32 +102,32 @@ class Caplet {
|
||||
|
||||
tweak {
|
||||
// wrong source
|
||||
command(highStreetBank.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", tradeDate, Tenor("6M")), 1.0.bd))) }
|
||||
|
||||
this `fails with` "relevant fixing must be included"
|
||||
}
|
||||
|
||||
tweak {
|
||||
// wrong date
|
||||
command(highStreetBank.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", tradeDate.plusYears(1), Tenor("6M")), 1.0.bd))) }
|
||||
|
||||
this `fails with` "relevant fixing must be included"
|
||||
}
|
||||
|
||||
tweak {
|
||||
// wrong tenor
|
||||
command(highStreetBank.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", tradeDate, Tenor("3M")), 1.0.bd))) }
|
||||
|
||||
this `fails with` "relevant fixing must be included"
|
||||
}
|
||||
|
||||
tweak {
|
||||
command(highStreetBank.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", tradeDate, Tenor("6M")), 1.5.bd))) }
|
||||
|
||||
this `fails with` "output state does not reflect fix command"
|
||||
}
|
||||
|
||||
command(highStreetBank.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", tradeDate, Tenor("6M")), 1.0.bd))) }
|
||||
|
||||
this.verifies()
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
package com.r3corda.contracts.universal
|
||||
|
||||
import com.r3corda.core.contracts.BusinessCalendar
|
||||
import com.r3corda.core.contracts.Frequency
|
||||
import com.r3corda.core.utilities.DUMMY_NOTARY
|
||||
import com.r3corda.testing.transaction
|
||||
import org.junit.Test
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Created by sofusmortensen on 08/09/16.
|
||||
*/
|
||||
|
||||
class RollOutTests {
|
||||
|
||||
val TEST_TX_TIME_1: Instant get() = Instant.parse("2017-09-02T12:00:00.00Z")
|
||||
|
||||
val contract = arrange {
|
||||
rollOut("2016-09-01".ld, "2017-09-01".ld, Frequency.Monthly) {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
"transfer".givenThat(after(end)) {
|
||||
highStreetBank.gives(acmeCorp, 10.K, USD)
|
||||
next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val stateStart = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contract)
|
||||
|
||||
val contractStep1a = arrange {
|
||||
rollOut("2016-12-01".ld, "2017-09-01".ld, Frequency.Monthly) {
|
||||
(acmeCorp or highStreetBank).may {
|
||||
"transfer".givenThat(after(end)) {
|
||||
highStreetBank.gives(acmeCorp, 10.K, USD)
|
||||
next()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val contractStep1b = arrange {
|
||||
highStreetBank.gives(acmeCorp, 10.K, USD)
|
||||
}
|
||||
|
||||
val stateStep1a = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractStep1a)
|
||||
val stateStep1b = UniversalContract.State(listOf(DUMMY_NOTARY.owningKey), contractStep1b)
|
||||
|
||||
@Test
|
||||
fun dateTests() {
|
||||
|
||||
val d1 = BusinessCalendar.parseDateFromString("2016-09-10")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun issue() {
|
||||
transaction {
|
||||
output { stateStart }
|
||||
timestamp(TEST_TX_TIME_1)
|
||||
|
||||
this `fails with` "transaction has a single command"
|
||||
|
||||
tweak {
|
||||
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
|
||||
this `fails with` "the transaction is signed by all liable parties"
|
||||
}
|
||||
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Issue() }
|
||||
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `execute`() {
|
||||
transaction {
|
||||
input { stateStart }
|
||||
output { stateStep1a }
|
||||
output { stateStep1b }
|
||||
timestamp(TEST_TX_TIME_1)
|
||||
|
||||
tweak {
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("some undefined name") }
|
||||
this `fails with` "action must be defined"
|
||||
}
|
||||
|
||||
command(highStreetBank.owningKey) { UniversalContract.Commands.Action("exercise") }
|
||||
|
||||
this.verifies()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -45,7 +45,7 @@ class Swaption {
|
||||
|
||||
|
||||
val elegant_contract = arrange {
|
||||
rollOut("01/04/2015", "01/04/2025", Frequency.Quarterly) {
|
||||
rollOut("01/04/2015".ld, "01/04/2025".ld, Frequency.Quarterly) {
|
||||
(highStreetBank or acmeCorp).may {
|
||||
"proceed".givenThat(after(start)) {
|
||||
highStreetBank.gives(acmeCorp, libor(notional, start, end), currency)
|
||||
@ -63,7 +63,7 @@ class Swaption {
|
||||
val strike = 1.2
|
||||
|
||||
val tarf = arrange {
|
||||
rollOut("01/04/2015", "01/04/2016", Frequency.Quarterly, object {
|
||||
rollOut("01/04/2015".ld, "01/04/2016".ld, Frequency.Quarterly, object {
|
||||
val cap = variable(150.K)
|
||||
}) {
|
||||
acmeCorp.may {
|
||||
@ -86,7 +86,7 @@ class Swaption {
|
||||
}
|
||||
|
||||
val tarf2 = arrange {
|
||||
rollOut("01/04/2015", "01/04/2016", Frequency.Quarterly, object {
|
||||
rollOut("01/04/2015".ld, "01/04/2016".ld, Frequency.Quarterly, object {
|
||||
val uses = variable(4)
|
||||
}) {
|
||||
acmeCorp.may {
|
||||
|
Loading…
x
Reference in New Issue
Block a user