mirror of
https://github.com/corda/corda.git
synced 2024-12-19 04:57:58 +00:00
universal: pretty print, type erasure workaround
This commit is contained in:
parent
336ce362e8
commit
abb361f207
@ -2,7 +2,9 @@ package net.corda.contracts.universal
|
|||||||
|
|
||||||
import net.corda.core.contracts.BusinessCalendar
|
import net.corda.core.contracts.BusinessCalendar
|
||||||
import net.corda.core.contracts.Tenor
|
import net.corda.core.contracts.Tenor
|
||||||
|
import net.corda.core.crypto.CompositeKey
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import java.lang.reflect.Type
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@ -110,17 +112,20 @@ data class CurrencyCross(val foreign: Currency, val domestic: Currency) : Percei
|
|||||||
|
|
||||||
operator fun Currency.div(currency: Currency) = CurrencyCross(this, currency)
|
operator fun Currency.div(currency: Currency) = CurrencyCross(this, currency)
|
||||||
|
|
||||||
data class PerceivableComparison<T>(val left: Perceivable<T>, val cmp: Comparison, val right: Perceivable<T>) : Perceivable<Boolean>
|
data class PerceivableComparison<T>(val left: Perceivable<T>, val cmp: Comparison, val right: Perceivable<T>, val type: Type) : Perceivable<Boolean>
|
||||||
|
|
||||||
infix fun Perceivable<BigDecimal>.lt(n: BigDecimal) = PerceivableComparison(this, Comparison.LT, const(n))
|
inline fun<reified T : Any> perceivableComparison(left: Perceivable<T>, cmp: Comparison, right: Perceivable<T>) =
|
||||||
infix fun Perceivable<BigDecimal>.gt(n: BigDecimal) = PerceivableComparison(this, Comparison.GT, const(n))
|
PerceivableComparison(left, cmp, right, T::class.java)
|
||||||
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>.lt(n: BigDecimal) = perceivableComparison(this, Comparison.LT, const(n))
|
||||||
infix fun Perceivable<BigDecimal>.gte(n: BigDecimal) = PerceivableComparison(this, Comparison.GTE, const(n))
|
infix fun Perceivable<BigDecimal>.gt(n: BigDecimal) = perceivableComparison(this, Comparison.GT, const(n))
|
||||||
infix fun Perceivable<BigDecimal>.lte(n: Double) = PerceivableComparison(this, Comparison.LTE, const(BigDecimal(n)))
|
infix fun Perceivable<BigDecimal>.lt(n: Double) = perceivableComparison(this, Comparison.LT, const(BigDecimal(n)))
|
||||||
infix fun Perceivable<BigDecimal>.gte(n: Double) = PerceivableComparison(this, Comparison.GTE, 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)))
|
||||||
|
|
||||||
enum class Operation {
|
enum class Operation {
|
||||||
PLUS, MINUS, TIMES, DIV
|
PLUS, MINUS, TIMES, DIV
|
||||||
@ -144,8 +149,7 @@ operator fun Perceivable<BigDecimal>.div(n: Double) = PerceivableOperation(this,
|
|||||||
operator fun Perceivable<Int>.plus(n: Int) = PerceivableOperation(this, Operation.PLUS, const(n))
|
operator fun Perceivable<Int>.plus(n: Int) = PerceivableOperation(this, Operation.PLUS, const(n))
|
||||||
operator fun Perceivable<Int>.minus(n: Int) = PerceivableOperation(this, Operation.MINUS, const(n))
|
operator fun Perceivable<Int>.minus(n: Int) = PerceivableOperation(this, Operation.MINUS, const(n))
|
||||||
|
|
||||||
class DummyPerceivable<T> : Perceivable<T>
|
data class TerminalEvent(val reference: Party, val source: CompositeKey) : Perceivable<Boolean>
|
||||||
|
|
||||||
|
|
||||||
// todo: holidays
|
// todo: holidays
|
||||||
data class Interest(val amount: Perceivable<BigDecimal>, val dayCountConvention: String,
|
data class Interest(val amount: Perceivable<BigDecimal>, val dayCountConvention: String,
|
||||||
|
@ -97,6 +97,27 @@ private class PrettyPrint(arr : Arrangement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is PerceivableComparison<*> -> {
|
||||||
|
when (per.type) {
|
||||||
|
BigDecimal::class.java -> prettyPrintPerBD(per.left as Perceivable<BigDecimal>)
|
||||||
|
Instant::class.java -> prettyPrintPerInstant(per.left as Perceivable<Instant>)
|
||||||
|
Boolean::class.java -> prettyPrintPerBoolean(per.left as Perceivable<Boolean>)
|
||||||
|
}
|
||||||
|
when (per.cmp) {
|
||||||
|
Comparison.GT -> print(" > ")
|
||||||
|
Comparison.LT -> print(" < ")
|
||||||
|
Comparison.GTE -> print(" >= ")
|
||||||
|
Comparison.LTE -> print(" <= ")
|
||||||
|
}
|
||||||
|
when (per.type) {
|
||||||
|
BigDecimal::class.java -> prettyPrintPerBD(per.right as Perceivable<BigDecimal>)
|
||||||
|
Instant::class.java -> prettyPrintPerInstant(per.right as Perceivable<Instant>)
|
||||||
|
Boolean::class.java -> prettyPrintPerBoolean(per.right as Perceivable<Boolean>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is TerminalEvent -> {
|
||||||
|
print("TerminalEvent(${partyMap[per.reference.owningKey]}, \"${per.source}\")")
|
||||||
|
}
|
||||||
is ActorPerceivable -> {
|
is ActorPerceivable -> {
|
||||||
print("signedBy(${partyMap[per.actor.owningKey]})")
|
print("signedBy(${partyMap[per.actor.owningKey]})")
|
||||||
}
|
}
|
||||||
@ -151,6 +172,9 @@ private class PrettyPrint(arr : Arrangement) {
|
|||||||
prettyPrintPerInstant(per.end)
|
prettyPrintPerInstant(per.end)
|
||||||
print(")")
|
print(")")
|
||||||
}
|
}
|
||||||
|
is CurrencyCross -> {
|
||||||
|
print("${per.foreign}/${per.domestic}")
|
||||||
|
}
|
||||||
else -> println(per)
|
else -> println(per)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ private fun signingParties(perceivable: Perceivable<Boolean>) : ImmutableSet<Par
|
|||||||
is PerceivableAnd -> Sets.union( signingParties( perceivable.left ), signingParties(perceivable.right) ).immutableCopy()
|
is PerceivableAnd -> Sets.union( signingParties( perceivable.left ), signingParties(perceivable.right) ).immutableCopy()
|
||||||
is PerceivableOr -> Sets.union( signingParties( perceivable.left ), signingParties(perceivable.right) ).immutableCopy()
|
is PerceivableOr -> Sets.union( signingParties( perceivable.left ), signingParties(perceivable.right) ).immutableCopy()
|
||||||
is TimePerceivable -> ImmutableSet.of<Party>()
|
is TimePerceivable -> ImmutableSet.of<Party>()
|
||||||
|
is TerminalEvent -> ImmutableSet.of( perceivable.reference )
|
||||||
|
is PerceivableComparison<*> -> ImmutableSet.of<Party>() // todo
|
||||||
else -> throw IllegalArgumentException("signingParties " + perceivable)
|
else -> throw IllegalArgumentException("signingParties " + perceivable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.contracts.universal
|
package net.corda.contracts.universal
|
||||||
|
|
||||||
import net.corda.core.crypto.Party
|
import net.corda.core.crypto.Party
|
||||||
|
import net.corda.core.crypto.composite
|
||||||
import net.corda.core.crypto.generateKeyPair
|
import net.corda.core.crypto.generateKeyPair
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -10,7 +11,7 @@ val acmeCorp = Party("ACME Corporation", generateKeyPair().public)
|
|||||||
val highStreetBank = Party("High Street Bank", generateKeyPair().public)
|
val highStreetBank = Party("High Street Bank", generateKeyPair().public)
|
||||||
val momAndPop = Party("Mom and Pop", generateKeyPair().public)
|
val momAndPop = Party("Mom and Pop", generateKeyPair().public)
|
||||||
|
|
||||||
val acmeCorporationHasDefaulted = DummyPerceivable<Boolean>()
|
val acmeCorporationHasDefaulted = TerminalEvent(acmeCorp, generateKeyPair().public.composite)
|
||||||
|
|
||||||
|
|
||||||
// Currencies
|
// Currencies
|
||||||
|
@ -0,0 +1,140 @@
|
|||||||
|
package net.corda.contracts.universal
|
||||||
|
|
||||||
|
import net.corda.core.contracts.USD
|
||||||
|
import org.junit.Ignore
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
// various example arrangements using basic syntax
|
||||||
|
|
||||||
|
class Examples {
|
||||||
|
|
||||||
|
val cds_contract = arrange {
|
||||||
|
actions {
|
||||||
|
acmeCorp may {
|
||||||
|
"claim".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
|
||||||
|
highStreetBank.owes(acmeCorp, 1.M, USD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fx swap
|
||||||
|
// both parties have the right to trigger the exchange of cash flows
|
||||||
|
val an_fx_swap = arrange {
|
||||||
|
actions {
|
||||||
|
(acmeCorp or highStreetBank) may {
|
||||||
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
|
highStreetBank.owes(acmeCorp, 1070.K, EUR)
|
||||||
|
acmeCorp.owes(highStreetBank, 1.M, USD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val american_fx_option = arrange {
|
||||||
|
actions {
|
||||||
|
acmeCorp may {
|
||||||
|
"exercise".givenThat(before("2017-09-01")) {
|
||||||
|
highStreetBank.owes(acmeCorp, 1070.K, EUR)
|
||||||
|
acmeCorp.owes(highStreetBank, 1.M, USD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val european_fx_option = arrange {
|
||||||
|
actions {
|
||||||
|
acmeCorp may {
|
||||||
|
"exercise".givenThat(before("2017-09-01")) {
|
||||||
|
fx_swap("2017-09-01", 1.M, 1.2.bd, EUR, USD, acmeCorp, highStreetBank)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(acmeCorp or highStreetBank) may {
|
||||||
|
"expire" anytime {
|
||||||
|
zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val contractZeroCouponBond = arrange {
|
||||||
|
actions {
|
||||||
|
acmeCorp may {
|
||||||
|
"execute".givenThat(after("2017-11-01")) {
|
||||||
|
highStreetBank.owes(acmeCorp, 1.M, USD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// maybe in the presence of negative interest rates you would want other side of contract to be able to take initiative as well
|
||||||
|
val zero_coupon_bond_2 = arrange {
|
||||||
|
actions {
|
||||||
|
(acmeCorp or highStreetBank) may {
|
||||||
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
|
highStreetBank.owes(acmeCorp, 1.M, USD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no touch
|
||||||
|
// Party Receiver
|
||||||
|
// Party Giver
|
||||||
|
//
|
||||||
|
// Giver has right to annul contract if barrier is breached
|
||||||
|
// Receiver has right to receive money at/after expiry
|
||||||
|
//
|
||||||
|
// Assume observable is using FX fixing
|
||||||
|
//
|
||||||
|
val no_touch = arrange {
|
||||||
|
actions {
|
||||||
|
(acmeCorp or highStreetBank) may {
|
||||||
|
"execute".givenThat(after("2017-09-01")) {
|
||||||
|
highStreetBank.owes(acmeCorp, 1.M, USD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
highStreetBank may {
|
||||||
|
"knock out".givenThat(EUR / USD gt 1.3) {
|
||||||
|
zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val one_touch = arrange {
|
||||||
|
actions {
|
||||||
|
highStreetBank may {
|
||||||
|
"expire".givenThat(after("2017-09-01")) {
|
||||||
|
zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acmeCorp may {
|
||||||
|
"knock in".givenThat(EUR / USD gt 1.3) {
|
||||||
|
highStreetBank.owes(acmeCorp, 1.M, USD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test @Ignore
|
||||||
|
fun `pretty print`() {
|
||||||
|
println ( prettyPrint(cds_contract) )
|
||||||
|
|
||||||
|
println ( prettyPrint(an_fx_swap) )
|
||||||
|
|
||||||
|
println ( prettyPrint(american_fx_option) )
|
||||||
|
|
||||||
|
println ( prettyPrint(european_fx_option) )
|
||||||
|
|
||||||
|
println ( prettyPrint(contractZeroCouponBond) )
|
||||||
|
|
||||||
|
println ( prettyPrint(zero_coupon_bond_2) )
|
||||||
|
|
||||||
|
println ( prettyPrint(no_touch) )
|
||||||
|
|
||||||
|
println ( prettyPrint(one_touch) )
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,114 +0,0 @@
|
|||||||
package net.corda.contracts.universal
|
|
||||||
|
|
||||||
import net.corda.core.contracts.USD
|
|
||||||
|
|
||||||
// various example arrangements using basic syntax
|
|
||||||
|
|
||||||
val cds_contract = arrange {
|
|
||||||
actions {
|
|
||||||
acmeCorp may {
|
|
||||||
"claim".givenThat(acmeCorporationHasDefaulted and before("2017-09-01")) {
|
|
||||||
highStreetBank.owes(acmeCorp, 1.M, USD)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fx swap
|
|
||||||
// both parties have the right to trigger the exchange of cash flows
|
|
||||||
val an_fx_swap = arrange {
|
|
||||||
actions {
|
|
||||||
(acmeCorp or highStreetBank) may {
|
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
|
||||||
highStreetBank.owes(acmeCorp, 1070.K, EUR)
|
|
||||||
acmeCorp.owes(highStreetBank, 1.M, USD)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val american_fx_option = arrange {
|
|
||||||
actions {
|
|
||||||
acmeCorp may {
|
|
||||||
"exercise".givenThat(before("2017-09-01")) {
|
|
||||||
highStreetBank.owes(acmeCorp, 1070.K, EUR)
|
|
||||||
acmeCorp.owes(highStreetBank, 1.M, USD)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val european_fx_option = arrange {
|
|
||||||
actions {
|
|
||||||
acmeCorp may {
|
|
||||||
"exercise".givenThat(before("2017-09-01")) {
|
|
||||||
fx_swap("2017-09-01", 1.M, 1.2.bd, EUR, USD, acmeCorp, highStreetBank)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(acmeCorp or highStreetBank) may {
|
|
||||||
"expire" anytime {
|
|
||||||
zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val contractZeroCouponBond = arrange {
|
|
||||||
actions {
|
|
||||||
acmeCorp may {
|
|
||||||
"execute".givenThat(after("2017-11-01")) {
|
|
||||||
highStreetBank.owes(acmeCorp, 1.M, USD)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// maybe in the presence of negative interest rates you would want other side of contract to be able to take initiative as well
|
|
||||||
val zero_coupon_bond_2 = arrange {
|
|
||||||
actions {
|
|
||||||
(acmeCorp or highStreetBank) may {
|
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
|
||||||
highStreetBank.owes(acmeCorp, 1.M, USD)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no touch
|
|
||||||
// Party Receiver
|
|
||||||
// Party Giver
|
|
||||||
//
|
|
||||||
// Giver has right to annul contract if barrier is breached
|
|
||||||
// Receiver has right to receive money at/after expiry
|
|
||||||
//
|
|
||||||
// Assume observable is using FX fixing
|
|
||||||
//
|
|
||||||
val no_touch = arrange {
|
|
||||||
actions {
|
|
||||||
(acmeCorp or highStreetBank) may {
|
|
||||||
"execute".givenThat(after("2017-09-01")) {
|
|
||||||
highStreetBank.owes(acmeCorp, 1.M, USD)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
highStreetBank may {
|
|
||||||
"knock out".givenThat(EUR / USD gt 1.3) {
|
|
||||||
zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val one_touch = arrange {
|
|
||||||
actions {
|
|
||||||
highStreetBank may {
|
|
||||||
"expire".givenThat(after("2017-09-01")) {
|
|
||||||
zero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
acmeCorp may {
|
|
||||||
"knock in".givenThat(EUR / USD gt 1.3) {
|
|
||||||
highStreetBank.owes(acmeCorp, 1.M, USD)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user