mirror of
https://github.com/corda/corda.git
synced 2024-12-18 20:47:57 +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.Tenor
|
||||
import net.corda.core.crypto.CompositeKey
|
||||
import net.corda.core.crypto.Party
|
||||
import java.lang.reflect.Type
|
||||
import java.math.BigDecimal
|
||||
import java.time.Instant
|
||||
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)
|
||||
|
||||
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))
|
||||
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)))
|
||||
inline fun<reified T : Any> perceivableComparison(left: Perceivable<T>, cmp: Comparison, right: Perceivable<T>) =
|
||||
PerceivableComparison(left, cmp, right, T::class.java)
|
||||
|
||||
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>.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>.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 {
|
||||
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>.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
|
||||
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 -> {
|
||||
print("signedBy(${partyMap[per.actor.owningKey]})")
|
||||
}
|
||||
@ -151,6 +172,9 @@ private class PrettyPrint(arr : Arrangement) {
|
||||
prettyPrintPerInstant(per.end)
|
||||
print(")")
|
||||
}
|
||||
is CurrencyCross -> {
|
||||
print("${per.foreign}/${per.domestic}")
|
||||
}
|
||||
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 PerceivableOr -> Sets.union( signingParties( perceivable.left ), signingParties(perceivable.right) ).immutableCopy()
|
||||
is TimePerceivable -> ImmutableSet.of<Party>()
|
||||
is TerminalEvent -> ImmutableSet.of( perceivable.reference )
|
||||
is PerceivableComparison<*> -> ImmutableSet.of<Party>() // todo
|
||||
else -> throw IllegalArgumentException("signingParties " + perceivable)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package net.corda.contracts.universal
|
||||
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.crypto.composite
|
||||
import net.corda.core.crypto.generateKeyPair
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
@ -10,7 +11,7 @@ val acmeCorp = Party("ACME Corporation", generateKeyPair().public)
|
||||
val highStreetBank = Party("High Street Bank", generateKeyPair().public)
|
||||
val momAndPop = Party("Mom and Pop", generateKeyPair().public)
|
||||
|
||||
val acmeCorporationHasDefaulted = DummyPerceivable<Boolean>()
|
||||
val acmeCorporationHasDefaulted = TerminalEvent(acmeCorp, generateKeyPair().public.composite)
|
||||
|
||||
|
||||
// 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