mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
Merge branch 'master' into dynamic-loading
This commit is contained in:
@ -83,7 +83,7 @@ class CommercialPaper : Contract {
|
||||
// Here, we match acceptable timestamp authorities by name. The list of acceptable TSAs (oracles) must be
|
||||
// hard coded into the contract because otherwise we could fail to gain consensus, if nodes disagree about
|
||||
// who or what is a trusted authority.
|
||||
val timestamp: TimestampCommand? = tx.commands.getTimestampByName("Mock Company 0", "Bank of Zurich")
|
||||
val timestamp: TimestampCommand? = tx.commands.getTimestampByName("Mock Company 0", "Bank A")
|
||||
|
||||
for (group in groups) {
|
||||
when (command.value) {
|
||||
|
@ -8,18 +8,8 @@
|
||||
|
||||
package contracts
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.JsonSerializer
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
import com.fasterxml.jackson.databind.type.SimpleType
|
||||
import core.*
|
||||
import core.crypto.SecureHash
|
||||
import core.node.services.DummyTimestampingAuthority
|
||||
import org.apache.commons.jexl3.JexlBuilder
|
||||
import org.apache.commons.jexl3.MapContext
|
||||
import java.math.BigDecimal
|
||||
@ -31,7 +21,16 @@ import java.util.*
|
||||
val IRS_PROGRAM_ID = InterestRateSwap()
|
||||
|
||||
// This is a placeholder for some types that we haven't identified exactly what they are just yet for things still in discussion
|
||||
open class UnknownType()
|
||||
open class UnknownType() {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return (other is UnknownType)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event superclass - everything happens on a date.
|
||||
@ -53,12 +52,12 @@ abstract class PaymentEvent(date: LocalDate) : Event(date) {
|
||||
* For the floating leg, the rate refers to a reference rate which is to be "fixed" at a point in the future.
|
||||
*/
|
||||
abstract class RatePaymentEvent(date: LocalDate,
|
||||
val accrualStartDate: LocalDate,
|
||||
val accrualEndDate: LocalDate,
|
||||
val dayCountBasisDay: DayCountBasisDay,
|
||||
val dayCountBasisYear: DayCountBasisYear,
|
||||
val notional: Amount,
|
||||
val rate: Rate) : PaymentEvent(date) {
|
||||
val accrualStartDate: LocalDate,
|
||||
val accrualEndDate: LocalDate,
|
||||
val dayCountBasisDay: DayCountBasisDay,
|
||||
val dayCountBasisYear: DayCountBasisYear,
|
||||
val notional: Amount,
|
||||
val rate: Rate) : PaymentEvent(date) {
|
||||
companion object {
|
||||
val CSVHeader = "AccrualStartDate,AccrualEndDate,DayCountFactor,Days,Date,Ccy,Notional,Rate,Flow"
|
||||
}
|
||||
@ -71,7 +70,7 @@ abstract class RatePaymentEvent(date: LocalDate,
|
||||
dayCountCalculator(accrualStartDate, accrualEndDate, dayCountBasisYear, dayCountBasisDay)
|
||||
|
||||
val dayCountFactor: BigDecimal get() =
|
||||
// TODO : Fix below (use daycount convention for division)
|
||||
// TODO : Fix below (use daycount convention for division)
|
||||
(BigDecimal(days).divide(BigDecimal(360.0), 8, RoundingMode.HALF_UP)).setScale(4, RoundingMode.HALF_UP)
|
||||
|
||||
open fun asCSV(): String = "$accrualStartDate,$accrualEndDate,$dayCountFactor,$days,$date,${notional.currency},${notional},$rate,$flow"
|
||||
@ -138,12 +137,6 @@ class FloatingRatePaymentEvent(date: LocalDate,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Don't try and use a rate that isn't ready yet.
|
||||
*/
|
||||
class DataNotReadyException : Exception()
|
||||
|
||||
|
||||
/**
|
||||
* The Interest Rate Swap class. For a quick overview of what an IRS is, see here - http://www.pimco.co.uk/EN/Education/Pages/InterestRateSwapsBasics1-08.aspx (no endorsement)
|
||||
* This contract has 4 significant data classes within it, the "Common", "Calculation", "FixedLeg" and "FloatingLeg"
|
||||
@ -240,6 +233,48 @@ class InterestRateSwap() : Contract {
|
||||
"TerminationDateAdjustment=$terminationDateAdjustment,DayCountBasis=$dayCountBasisDay/$dayCountBasisYear,DayInMonth=$dayInMonth," +
|
||||
"PaymentRule=$paymentRule,PaymentDelay=$paymentDelay,PaymentCalendar=$paymentCalendar,InterestPeriodAdjustment=$interestPeriodAdjustment"
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
|
||||
other as CommonLeg
|
||||
|
||||
if (notional != other.notional) return false
|
||||
if (paymentFrequency != other.paymentFrequency) return false
|
||||
if (effectiveDate != other.effectiveDate) return false
|
||||
if (effectiveDateAdjustment != other.effectiveDateAdjustment) return false
|
||||
if (terminationDate != other.terminationDate) return false
|
||||
if (terminationDateAdjustment != other.terminationDateAdjustment) return false
|
||||
if (dayCountBasisDay != other.dayCountBasisDay) return false
|
||||
if (dayCountBasisYear != other.dayCountBasisYear) return false
|
||||
if (dayInMonth != other.dayInMonth) return false
|
||||
if (paymentRule != other.paymentRule) return false
|
||||
if (paymentDelay != other.paymentDelay) return false
|
||||
if (paymentCalendar != other.paymentCalendar) return false
|
||||
if (interestPeriodAdjustment != other.interestPeriodAdjustment) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = notional.hashCode()
|
||||
result += 31 * result + paymentFrequency.hashCode()
|
||||
result += 31 * result + effectiveDate.hashCode()
|
||||
result += 31 * result + (effectiveDateAdjustment?.hashCode() ?: 0)
|
||||
result += 31 * result + terminationDate.hashCode()
|
||||
result += 31 * result + (terminationDateAdjustment?.hashCode() ?: 0)
|
||||
result += 31 * result + dayCountBasisDay.hashCode()
|
||||
result += 31 * result + dayCountBasisYear.hashCode()
|
||||
result += 31 * result + dayInMonth
|
||||
result += 31 * result + paymentRule.hashCode()
|
||||
result += 31 * result + paymentDelay
|
||||
result += 31 * result + paymentCalendar.hashCode()
|
||||
result += 31 * result + interestPeriodAdjustment.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
open class FixedLeg(
|
||||
@ -264,6 +299,29 @@ class InterestRateSwap() : Contract {
|
||||
dayCountBasisDay, dayCountBasisYear, dayInMonth, paymentRule, paymentDelay, paymentCalendar, interestPeriodAdjustment) {
|
||||
override fun toString(): String = "FixedLeg(Payer=$fixedRatePayer," + super.toString() + ",fixedRate=$fixedRate," +
|
||||
"rollConvention=$rollConvention"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
if (!super.equals(other)) return false
|
||||
|
||||
other as FixedLeg
|
||||
|
||||
if (fixedRatePayer != other.fixedRatePayer) return false
|
||||
if (fixedRate != other.fixedRate) return false
|
||||
if (rollConvention != other.rollConvention) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = super.hashCode()
|
||||
result += 31 * result + fixedRatePayer.hashCode()
|
||||
result += 31 * result + fixedRate.hashCode()
|
||||
result += 31 * result + rollConvention.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
open class FloatingLeg(
|
||||
@ -298,6 +356,44 @@ class InterestRateSwap() : Contract {
|
||||
"FixingPeriond=$fixingPeriod,ResetRule=$resetRule,FixingsPerPayment=$fixingsPerPayment,FixingCalendar=$fixingCalendar," +
|
||||
"Index=$index,IndexSource=$indexSource,IndexTenor=$indexTenor"
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
if (!super.equals(other)) return false
|
||||
|
||||
other as FloatingLeg
|
||||
|
||||
if (floatingRatePayer != other.floatingRatePayer) return false
|
||||
if (rollConvention != other.rollConvention) return false
|
||||
if (fixingRollConvention != other.fixingRollConvention) return false
|
||||
if (resetDayInMonth != other.resetDayInMonth) return false
|
||||
if (fixingPeriod != other.fixingPeriod) return false
|
||||
if (resetRule != other.resetRule) return false
|
||||
if (fixingsPerPayment != other.fixingsPerPayment) return false
|
||||
if (fixingCalendar != other.fixingCalendar) return false
|
||||
if (index != other.index) return false
|
||||
if (indexSource != other.indexSource) return false
|
||||
if (indexTenor != other.indexTenor) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = super.hashCode()
|
||||
result += 31 * result + floatingRatePayer.hashCode()
|
||||
result += 31 * result + rollConvention.hashCode()
|
||||
result += 31 * result + fixingRollConvention.hashCode()
|
||||
result += 31 * result + resetDayInMonth
|
||||
result += 31 * result + fixingPeriod.hashCode()
|
||||
result += 31 * result + resetRule.hashCode()
|
||||
result += 31 * result + fixingsPerPayment.hashCode()
|
||||
result += 31 * result + fixingCalendar.hashCode()
|
||||
result += 31 * result + index.hashCode()
|
||||
result += 31 * result + indexSource.hashCode()
|
||||
result += 31 * result + indexTenor.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -305,7 +401,7 @@ class InterestRateSwap() : Contract {
|
||||
*/
|
||||
override fun verify(tx: TransactionForVerification) {
|
||||
val command = tx.commands.requireSingleCommand<InterestRateSwap.Commands>()
|
||||
val time = tx.commands.getTimestampByName("Mock Company 0", "Bank of Zurich")?.midpoint
|
||||
val time = tx.commands.getTimestampByName("Mock Company 0", "European Timestamping Service", "Bank A")?.midpoint
|
||||
if (time == null) throw IllegalArgumentException("must be timestamped")
|
||||
|
||||
val irs = tx.outStates.filterIsInstance<InterestRateSwap.State>().single()
|
||||
@ -356,7 +452,8 @@ class InterestRateSwap() : Contract {
|
||||
val floatingLeg: FloatingLeg,
|
||||
val calculation: Calculation,
|
||||
val common: Common
|
||||
) : LinearState {
|
||||
) : FixableDealState {
|
||||
|
||||
override val contract = IRS_PROGRAM_ID
|
||||
override val thread = SecureHash.sha256(common.tradeID)
|
||||
override val ref = common.tradeID
|
||||
@ -365,6 +462,39 @@ class InterestRateSwap() : Contract {
|
||||
return (fixedLeg.fixedRatePayer.owningKey in ourKeys) || (floatingLeg.floatingRatePayer.owningKey in ourKeys)
|
||||
}
|
||||
|
||||
override val parties: Array<Party>
|
||||
get() = arrayOf(fixedLeg.fixedRatePayer, floatingLeg.floatingRatePayer)
|
||||
|
||||
override fun withPublicKey(before: Party, after: PublicKey): State {
|
||||
val newParty = Party(before.name, after)
|
||||
if (before == fixedLeg.fixedRatePayer) {
|
||||
val deal = copy()
|
||||
deal.fixedLeg.fixedRatePayer = newParty
|
||||
return deal
|
||||
} else if (before == floatingLeg.floatingRatePayer) {
|
||||
val deal = copy()
|
||||
deal.floatingLeg.floatingRatePayer = newParty
|
||||
return deal
|
||||
} else {
|
||||
throw IllegalArgumentException("No such party: $before")
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateAgreement(): TransactionBuilder = InterestRateSwap().generateAgreement(floatingLeg, fixedLeg, calculation, common)
|
||||
|
||||
override fun generateFix(ptx: TransactionBuilder, oldStateRef: StateRef, fix: Fix) {
|
||||
InterestRateSwap().generateFix(ptx, StateAndRef(this, oldStateRef), Pair(fix.of.forDay, Rate(RatioUnit(fix.value))))
|
||||
}
|
||||
|
||||
override fun nextFixingOf(): FixOf? {
|
||||
val date = calculation.nextFixingDate()
|
||||
return if (date == null) null else {
|
||||
val fixingEvent = calculation.getFixing(date)
|
||||
val oracleRate = fixingEvent.rate as ReferenceRate
|
||||
FixOf(oracleRate.name, date, oracleRate.tenor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For evaluating arbitrary java on the platform
|
||||
*/
|
||||
|
@ -1,17 +1,8 @@
|
||||
package contracts
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer
|
||||
import com.fasterxml.jackson.databind.type.SimpleType
|
||||
import core.Amount
|
||||
import core.Tenor
|
||||
import core.*
|
||||
import java.math.BigDecimal
|
||||
import java.time.LocalDate
|
||||
import java.security.PublicKey
|
||||
|
||||
|
||||
// Things in here will move to the general utils class when we've hammered out various discussions regarding amounts, dates, oracle etc.
|
||||
@ -21,6 +12,22 @@ import java.time.LocalDate
|
||||
*/
|
||||
open class RatioUnit(value: BigDecimal) { // TODO: Discuss this type
|
||||
val value = value
|
||||
|
||||
override fun equals(other: Any?): Boolean{
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
|
||||
other as RatioUnit
|
||||
|
||||
if (value != other.value) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int{
|
||||
return value.hashCode()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,10 +44,78 @@ open class PercentageRatioUnit(percentageAsString: String) : RatioUnit(BigDecima
|
||||
*/
|
||||
val String.percent: PercentageRatioUnit get() = PercentageRatioUnit(this)
|
||||
|
||||
/**
|
||||
* Interface representing an agreement that exposes various attributes that are common and allow
|
||||
* implementation of general protocols that manipulate many agreement types
|
||||
*/
|
||||
interface DealState : LinearState {
|
||||
|
||||
/** Human readable well known reference (e.g. trade reference) */
|
||||
val ref: String
|
||||
|
||||
/** Exposes the Parties involved in a generic way */
|
||||
val parties: Array<Party>
|
||||
|
||||
/** Allow swapping in of potentially transaction specific public keys prior to signing */
|
||||
fun withPublicKey(before: Party, after: PublicKey): DealState
|
||||
|
||||
/**
|
||||
* Generate a partial transaction representing an agreement (command) to this deal, allowing a general
|
||||
* deal/agreement protocol to generate the necessary transaction for potential implementations
|
||||
*
|
||||
* TODO: Currently this is the "inception" transaction but in future an offer of some description might be an input state ref
|
||||
*
|
||||
* TODO: This should more likely be a method on the Contract (on a common interface) and the changes to reference a
|
||||
* Contract instance from a ContractState are imminent, at which point we can move this out of here
|
||||
*/
|
||||
fun generateAgreement(): TransactionBuilder
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface adding fixing specific methods
|
||||
*/
|
||||
interface FixableDealState : DealState {
|
||||
/**
|
||||
* When is the next fixing and what is the fixing for?
|
||||
*
|
||||
* TODO: In future we would use this to register for an event to trigger a/the fixing protocol
|
||||
*/
|
||||
fun nextFixingOf(): FixOf?
|
||||
|
||||
/**
|
||||
* Generate a fixing command for this deal and fix
|
||||
*
|
||||
* TODO: This would also likely move to methods on the Contract once the changes to reference
|
||||
* the Contract from the ContractState are in
|
||||
*/
|
||||
fun generateFix(ptx: TransactionBuilder, oldStateRef: StateRef, fix: Fix)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent of the Rate family. Used to denote fixed rates, floating rates, reference rates etc
|
||||
*/
|
||||
open class Rate(val ratioUnit: RatioUnit? = null)
|
||||
open class Rate(val ratioUnit: RatioUnit? = null) {
|
||||
|
||||
override fun equals(other: Any?): Boolean{
|
||||
if (this === other) return true
|
||||
if (other?.javaClass != javaClass) return false
|
||||
|
||||
other as Rate
|
||||
|
||||
if (ratioUnit != other.ratioUnit) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the hash code of the ratioUnit or zero if the ratioUnit is null, as is the case for floating rate fixings
|
||||
* that have not yet happened. Yet-to-be fixed floating rates need to be equal such that schedules can be tested
|
||||
* for equality.
|
||||
*/
|
||||
override fun hashCode(): Int{
|
||||
return ratioUnit?.hashCode() ?: 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A very basic subclass to represent a fixed rate.
|
||||
|
Reference in New Issue
Block a user