Updated Corda in preparation for the merging of the Vega cordapp. Includes

some minor changes, including gitignore rule changes. The largest change
is replacing the current fresh key for each transaction with a single
static identity in preparation for aimproved and more fleshed out key
sharing infrastructure.
This commit is contained in:
Clinton Alexander 2016-09-26 13:02:33 +01:00
parent 6c96517f6f
commit 43de27c4c1
21 changed files with 65 additions and 74 deletions

26
.gitignore vendored
View File

@ -5,20 +5,28 @@
tags tags
.DS_Store .DS_Store
*.log *.log
*.log.gz
*.orig
# Created by .ignore support plugin (hsz.mobi) # Created by .ignore support plugin (hsz.mobi)
.gradle .gradle
/build/
/node/build/
/contracts/build
/contracts/isolated/build
/core/build
/experimental/build
/docs/build/doctrees /docs/build/doctrees
/test-utils/build
/client/build # General build files
/explorer/build **/build/classes/**
**/build/install/**
**/build/kotlin-classes/**
**/build/libs/**
**/build/resources/**
**/build/tmp/**
**/build/reports/**
**/build/jacoco/***
**/build/test-results/**
**/build/[0-9]*/**
**/build/nodes/**
**/build/scripts/**
**/build/publications/**
# gradle's buildSrc build/ # gradle's buildSrc build/
/buildSrc/build/ /buildSrc/build/

View File

@ -201,7 +201,7 @@ class InterestRateSwap() : Contract {
val threshold: Amount<Currency>, val threshold: Amount<Currency>,
val minimumTransferAmount: Amount<Currency>, val minimumTransferAmount: Amount<Currency>,
val rounding: Amount<Currency>, val rounding: Amount<Currency>,
val valuationDate: String, val valuationDateDescription: String, // This describes (in english) how regularly the swap is to be valued, e.g. "every local working day"
val notificationTime: String, val notificationTime: String,
val resolutionTime: String, val resolutionTime: String,
val interestRate: ReferenceRate, val interestRate: ReferenceRate,
@ -679,22 +679,6 @@ class InterestRateSwap() : Contract {
return ScheduledActivity(protocolLogicRefFactory.create(TwoPartyDealProtocol.FixingRoleDecider::class.java, thisStateRef, duration), instant) return ScheduledActivity(protocolLogicRefFactory.create(TwoPartyDealProtocol.FixingRoleDecider::class.java, thisStateRef, duration), instant)
} }
// TODO: This changing of the public key violates the assumption that Party is a fixed identity key.
override fun withPublicKey(before: Party, after: PublicKey): DealState {
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(notary: Party): TransactionBuilder = InterestRateSwap().generateAgreement(floatingLeg, fixedLeg, calculation, common, notary) override fun generateAgreement(notary: Party): TransactionBuilder = InterestRateSwap().generateAgreement(floatingLeg, fixedLeg, calculation, common, notary)
override fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix) { override fun generateFix(ptx: TransactionBuilder, oldState: StateAndRef<*>, fix: Fix) {

View File

@ -6,11 +6,8 @@ import com.r3corda.core.transactions.SignedTransaction
import com.r3corda.core.utilities.DUMMY_NOTARY import com.r3corda.core.utilities.DUMMY_NOTARY
import com.r3corda.core.utilities.DUMMY_NOTARY_KEY import com.r3corda.core.utilities.DUMMY_NOTARY_KEY
import com.r3corda.core.utilities.TEST_TX_TIME import com.r3corda.core.utilities.TEST_TX_TIME
import com.r3corda.testing.LedgerDSL
import com.r3corda.testing.TestLedgerDSLInterpreter
import com.r3corda.testing.TestTransactionDSLInterpreter
import com.r3corda.testing.node.MockServices
import com.r3corda.testing.* import com.r3corda.testing.*
import com.r3corda.testing.node.MockServices
import org.junit.Test import org.junit.Test
import java.math.BigDecimal import java.math.BigDecimal
import java.time.LocalDate import java.time.LocalDate
@ -92,7 +89,7 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
threshold = Amount(0, EUR), threshold = Amount(0, EUR),
minimumTransferAmount = Amount(250000 * 100, EUR), minimumTransferAmount = Amount(250000 * 100, EUR),
rounding = Amount(10000 * 100, EUR), rounding = Amount(10000 * 100, EUR),
valuationDate = "Every Local Business Day", valuationDateDescription = "Every Local Business Day",
notificationTime = "2:00pm London", notificationTime = "2:00pm London",
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ", resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"), interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),
@ -182,7 +179,7 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
threshold = Amount(0, EUR), threshold = Amount(0, EUR),
minimumTransferAmount = Amount(250000 * 100, EUR), minimumTransferAmount = Amount(250000 * 100, EUR),
rounding = Amount(10000 * 100, EUR), rounding = Amount(10000 * 100, EUR),
valuationDate = "Every Local Business Day", valuationDateDescription = "Every Local Business Day",
notificationTime = "2:00pm London", notificationTime = "2:00pm London",
resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ", resolutionTime = "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"), interestRate = ReferenceRate("T3270", Tenor("6M"), "EONIA"),

View File

@ -23,6 +23,7 @@ fun commodity(code: String) = Commodity.getInstance(code)!!
@JvmField val USD = currency("USD") @JvmField val USD = currency("USD")
@JvmField val GBP = currency("GBP") @JvmField val GBP = currency("GBP")
@JvmField val EUR = currency("EUR")
@JvmField val CHF = currency("CHF") @JvmField val CHF = currency("CHF")
@JvmField val FCOJ = commodity("FCOJ") @JvmField val FCOJ = commodity("FCOJ")

View File

@ -279,9 +279,6 @@ interface DealState : LinearState {
/** Exposes the Parties involved in a generic way */ /** Exposes the Parties involved in a generic way */
val parties: List<Party> val parties: List<Party>
// TODO: This works by editing the keys used by a Party which is invalid.
fun withPublicKey(before: Party, after: PublicKey): DealState
/** /**
* Generate a partial transaction representing an agreement (command) to this deal, allowing a general * 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. * deal/agreement protocol to generate the necessary transaction for potential implementations.

View File

@ -231,7 +231,7 @@ object X509Utilities {
fun generateECDSAKeyPairForSSL(): KeyPair { fun generateECDSAKeyPairForSSL(): KeyPair {
val keyGen = KeyPairGenerator.getInstance(KEY_GENERATION_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME) val keyGen = KeyPairGenerator.getInstance(KEY_GENERATION_ALGORITHM, BouncyCastleProvider.PROVIDER_NAME)
val ecSpec = ECGenParameterSpec(ECDSA_CURVE) // Force named curve, because TLS implementations don't support many curves val ecSpec = ECGenParameterSpec(ECDSA_CURVE) // Force named curve, because TLS implementations don't support many curves
keyGen.initialize(ecSpec, SecureRandom()) keyGen.initialize(ecSpec, newSecureRandom())
return keyGen.generateKeyPair() return keyGen.generateKeyPair()
} }

View File

@ -150,6 +150,10 @@ interface VaultService {
} }
inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java) inline fun <reified T : LinearState> VaultService.linearHeadsOfType() = linearHeadsOfType_(T::class.java)
inline fun <reified T : DealState> VaultService.dealsWith(party: Party) = linearHeadsOfType<T>().values.filter {
// TODO: Replace name comparison with full party comparison (keys are currenty not equal)
it.state.data.parties.any { it.name == party.name }
}
/** /**
* The KMS is responsible for storing and using private keys to sign things. An implementation of this may, for example, * The KMS is responsible for storing and using private keys to sign things. An implementation of this may, for example,

View File

@ -2,8 +2,11 @@ package com.r3corda.core.protocols
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.messaging.Message
import com.r3corda.core.messaging.runOnNextMessage
import com.r3corda.core.node.ServiceHub import com.r3corda.core.node.ServiceHub
import com.r3corda.core.node.services.DEFAULT_SESSION_ID import com.r3corda.core.node.services.DEFAULT_SESSION_ID
import com.r3corda.core.serialization.deserialize
import com.r3corda.core.utilities.ProgressTracker import com.r3corda.core.utilities.ProgressTracker
import com.r3corda.core.utilities.UntrustworthyData import com.r3corda.core.utilities.UntrustworthyData
import com.r3corda.core.utilities.debug import com.r3corda.core.utilities.debug
@ -11,6 +14,7 @@ import com.r3corda.protocols.HandshakeMessage
import org.slf4j.Logger import org.slf4j.Logger
import rx.Observable import rx.Observable
import java.util.* import java.util.*
import java.util.concurrent.CompletableFuture
/** /**
* A sub-class of [ProtocolLogic<T>] implements a protocol flow using direct, straight line blocking code. Thus you * A sub-class of [ProtocolLogic<T>] implements a protocol flow using direct, straight line blocking code. Thus you
@ -108,6 +112,11 @@ abstract class ProtocolLogic<out T> {
throw IllegalStateException("Session with party $otherParty hasn't been established yet") throw IllegalStateException("Session with party $otherParty hasn't been established yet")
} }
/**
* Check if we already have a session with this party
*/
protected fun hasSession(otherParty: Party) = sessions.containsKey(otherParty)
/** /**
* Invokes the given subprotocol by simply passing through this [ProtocolLogic]s reference to the * Invokes the given subprotocol by simply passing through this [ProtocolLogic]s reference to the
* [ProtocolStateMachine] and then calling the [call] method. * [ProtocolStateMachine] and then calling the [call] method.

View File

@ -70,8 +70,8 @@ abstract class AbstractStateReplacementProtocol<T> {
return finalTx.tx.outRef(0) return finalTx.tx.outRef(0)
} }
abstract internal fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): Proposal<T> abstract protected fun assembleProposal(stateRef: StateRef, modification: T, stx: SignedTransaction): Proposal<T>
abstract internal fun assembleTx(): Pair<SignedTransaction, List<PublicKey>> abstract protected fun assembleTx(): Pair<SignedTransaction, List<PublicKey>>
@Suspendable @Suspendable
private fun collectSignatures(participants: List<PublicKey>, stx: SignedTransaction): List<DigitalSignature.WithKey> { private fun collectSignatures(participants: List<PublicKey>, stx: SignedTransaction): List<DigitalSignature.WithKey> {
@ -93,7 +93,10 @@ abstract class AbstractStateReplacementProtocol<T> {
private fun getParticipantSignature(party: Party, stx: SignedTransaction): DigitalSignature.WithKey { private fun getParticipantSignature(party: Party, stx: SignedTransaction): DigitalSignature.WithKey {
val proposal = assembleProposal(originalState.ref, modification, stx) val proposal = assembleProposal(originalState.ref, modification, stx)
send(party, Handshake(serviceHub.storageService.myLegalIdentity)) // TODO: Move this into protocol logic as a func on the lines of handshake(Party, HandshakeMessage)
if (!hasSession(party)) {
send(party, Handshake(serviceHub.storageService.myLegalIdentity))
}
val response = sendAndReceive<Result>(party, proposal) val response = sendAndReceive<Result>(party, proposal)
val participantSignature = response.unwrap { val participantSignature = response.unwrap {
@ -179,7 +182,7 @@ abstract class AbstractStateReplacementProtocol<T> {
* on the change proposed, and may further depend on the node itself (for example configuration). The * on the change proposed, and may further depend on the node itself (for example configuration). The
* proposal is returned if acceptable, otherwise an exception is thrown. * proposal is returned if acceptable, otherwise an exception is thrown.
*/ */
abstract fun verifyProposal(maybeProposal: UntrustworthyData<Proposal<T>>): Proposal<T> abstract protected fun verifyProposal(maybeProposal: UntrustworthyData<Proposal<T>>): Proposal<T>
@Suspendable @Suspendable
private fun verifyTx(stx: SignedTransaction) { private fun verifyTx(stx: SignedTransaction) {
@ -219,4 +222,4 @@ class StateReplacementRefused(val identity: Party, val state: StateRef, val deta
override fun toString() = "A participant $identity refused to change state $state: " + (detail ?: "no reason provided") override fun toString() = "A participant $identity refused to change state $state: " + (detail ?: "no reason provided")
} }
class StateReplacementException(val error: StateReplacementRefused) : Exception("State change failed - $error") class StateReplacementException(val error: StateReplacementRefused) : Exception("State change failed - $error")

View File

@ -6,6 +6,7 @@ import com.r3corda.core.contracts.*
import com.r3corda.core.crypto.DigitalSignature import com.r3corda.core.crypto.DigitalSignature
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.signWithECDSA import com.r3corda.core.crypto.signWithECDSA
import com.r3corda.core.crypto.toBase58String
import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.ServiceType import com.r3corda.core.node.services.ServiceType
import com.r3corda.core.protocols.ProtocolLogic import com.r3corda.core.protocols.ProtocolLogic
@ -285,22 +286,11 @@ object TwoPartyDealProtocol {
override fun validateHandshake(handshake: Handshake<T>): Handshake<T> { override fun validateHandshake(handshake: Handshake<T>): Handshake<T> {
// What is the seller trying to sell us? // What is the seller trying to sell us?
val deal: T = handshake.payload val deal: T = handshake.payload
val otherKey = handshake.publicKey
logger.trace { "Got deal request for: ${handshake.payload.ref}" } logger.trace { "Got deal request for: ${handshake.payload.ref}" }
check(dealToBuy == deal) check(dealToBuy == deal)
// We need to substitute in the new public keys for the Parties return handshake.copy(payload = deal)
val myName = serviceHub.storageService.myLegalIdentity.name
val myOldParty = deal.parties.single { it.name == myName }
val theirOldParty = deal.parties.single { it.name != myName }
@Suppress("UNCHECKED_CAST")
val newDeal = deal.
withPublicKey(myOldParty, serviceHub.keyManagementService.freshKey().public).
withPublicKey(theirOldParty, otherKey) as T
return handshake.copy(payload = newDeal)
} }

View File

@ -261,7 +261,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
private fun scheduleTX(instant: Instant, increment: Int = 1): ScheduledStateRef? { private fun scheduleTX(instant: Instant, increment: Int = 1): ScheduledStateRef? {
var scheduledRef: ScheduledStateRef? = null var scheduledRef: ScheduledStateRef? = null
apply { apply {
val freshKey = services.keyManagementService.freshKey() val freshKey = services.storageService.myLegalIdentityKey
val state = TestState(factory.create(TestProtocolLogic::class.java, increment), instant) val state = TestState(factory.create(TestProtocolLogic::class.java, increment), instant)
val usefulTX = TransactionType.General.Builder(null).apply { val usefulTX = TransactionType.General.Builder(null).apply {
addOutputState(state, DUMMY_NOTARY) addOutputState(state, DUMMY_NOTARY)

View File

@ -83,7 +83,7 @@ class VaultWithCashTest {
fun `issue and spend total correctly and irrelevant ignored`() { fun `issue and spend total correctly and irrelevant ignored`() {
databaseTransaction(database) { databaseTransaction(database) {
// A tx that sends us money. // A tx that sends us money.
val freshKey = services.keyManagementService.freshKey() val freshKey = services.storageService.myLegalIdentityKey
val usefulTX = TransactionType.General.Builder(null).apply { val usefulTX = TransactionType.General.Builder(null).apply {
Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY) Cash().generateIssue(this, 100.DOLLARS `issued by` MEGA_CORP.ref(1), freshKey.public, DUMMY_NOTARY)
signWith(MEGA_CORP_KEY) signWith(MEGA_CORP_KEY)
@ -121,7 +121,7 @@ class VaultWithCashTest {
@Test @Test
fun `branching LinearStates fails to verify`() { fun `branching LinearStates fails to verify`() {
databaseTransaction(database) { databaseTransaction(database) {
val freshKey = services.keyManagementService.freshKey() val freshKey = services.storageService.myLegalIdentityKey
val linearId = UniqueIdentifier() val linearId = UniqueIdentifier()
// Issue a linear state // Issue a linear state
@ -141,7 +141,7 @@ class VaultWithCashTest {
@Test @Test
fun `sequencing LinearStates works`() { fun `sequencing LinearStates works`() {
databaseTransaction(database) { databaseTransaction(database) {
val freshKey = services.keyManagementService.freshKey() val freshKey = services.storageService.myLegalIdentityKey
val linearId = UniqueIdentifier() val linearId = UniqueIdentifier()

View File

@ -85,7 +85,7 @@ fun main(args: Array<String>) {
// Make a garbage transaction that includes a rate fix. // Make a garbage transaction that includes a rate fix.
val tx = TransactionType.General.Builder(notaryNode.identity) val tx = TransactionType.General.Builder(notaryNode.identity)
tx.addOutputState(TransactionState(Cash.State(1500.DOLLARS `issued by` node.storage.myLegalIdentity.ref(1), node.keyManagement.freshKey().public), notaryNode.identity)) tx.addOutputState(TransactionState(Cash.State(1500.DOLLARS `issued by` node.storage.myLegalIdentity.ref(1), node.storage.myLegalIdentityKey.public), notaryNode.identity))
val protocol = RatesFixProtocol(tx, rateOracle.identity, fixOf, expectedRate, rateTolerance) val protocol = RatesFixProtocol(tx, rateOracle.identity, fixOf, expectedRate, rateTolerance)
node.services.startProtocol("demo.ratefix", protocol).get() node.services.startProtocol("demo.ratefix", protocol).get()
node.stop() node.stop()

View File

@ -202,7 +202,7 @@ private fun runBuyer(node: Node, amount: Amount<Currency>) {
databaseTransaction(node.database) { databaseTransaction(node.database) {
node.services.fillWithSomeTestCash(300000.DOLLARS, node.services.fillWithSomeTestCash(300000.DOLLARS,
outputNotary = node.info.identity, // In this demo, the buyer and notary are the same. outputNotary = node.info.identity, // In this demo, the buyer and notary are the same.
ownedBy = node.services.keyManagementService.freshKey().public) ownedBy = node.storage.myLegalIdentityKey.public)
} }
// Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band // Wait around until a node asks to start a trade with us. In a real system, this part would happen out of band
@ -314,7 +314,7 @@ private class TraderDemoProtocolSeller(val otherSide: Party,
progressTracker.currentStep = SELF_ISSUING progressTracker.currentStep = SELF_ISSUING
val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0] val notary: NodeInfo = serviceHub.networkMapCache.notaryNodes[0]
val cpOwnerKey = serviceHub.keyManagementService.freshKey() val cpOwnerKey = serviceHub.storageService.myLegalIdentityKey
val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public, notary) val commercialPaper = selfIssueSomeCommercialPaper(cpOwnerKey.public, notary)
progressTracker.currentStep = TRADING progressTracker.currentStep = TRADING

View File

@ -107,7 +107,7 @@ object AutoOfferProtocol {
otherParty, otherParty,
notary, notary,
dealToBeOffered, dealToBeOffered,
serviceHub.keyManagementService.freshKey(), serviceHub.storageService.myLegalIdentityKey,
progressTracker.getChildProgressTracker(DEALING)!! progressTracker.getChildProgressTracker(DEALING)!!
) )
val stx = subProtocol(instigator, inheritParentSessions = true) val stx = subProtocol(instigator, inheritParentSessions = true)

View File

@ -32,17 +32,11 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
currentDateAndTime = LocalDate.of(2016, 3, 8).atStartOfDay() currentDateAndTime = LocalDate.of(2016, 3, 8).atStartOfDay()
} }
private var nodeAKey: KeyPair? = null
private var nodeBKey: KeyPair? = null
private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>()) private val executeOnNextIteration = Collections.synchronizedList(LinkedList<() -> Unit>())
override fun startMainSimulation(): ListenableFuture<Unit> { override fun startMainSimulation(): ListenableFuture<Unit> {
val future = SettableFuture.create<Unit>() val future = SettableFuture.create<Unit>()
nodeAKey = banks[0].keyManagement.freshKey()
nodeBKey = banks[1].keyManagement.freshKey()
startIRSDealBetween(0, 1).success { startIRSDealBetween(0, 1).success {
// Next iteration is a pause. // Next iteration is a pause.
executeOnNextIteration.add {} executeOnNextIteration.add {}
@ -121,7 +115,7 @@ class IRSSimulation(networkSendManuallyPumped: Boolean, runAsync: Boolean, laten
irs.fixedLeg.fixedRatePayer = node1.info.identity irs.fixedLeg.fixedRatePayer = node1.info.identity
irs.floatingLeg.floatingRatePayer = node2.info.identity irs.floatingLeg.floatingRatePayer = node2.info.identity
val instigator = TwoPartyDealProtocol.Instigator(node2.info.identity, notary.info.identity, irs, nodeAKey!!) val instigator = TwoPartyDealProtocol.Instigator(node2.info.identity, notary.info.identity, irs, node1.keyPair!!)
val acceptor = TwoPartyDealProtocol.Acceptor(node1.info.identity, notary.info.identity, irs) val acceptor = TwoPartyDealProtocol.Acceptor(node1.info.identity, notary.info.identity, irs)
connectProtocols(instigator, acceptor) connectProtocols(instigator, acceptor)

View File

@ -3,6 +3,7 @@ package com.r3corda.simulation
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.google.common.util.concurrent.Futures import com.google.common.util.concurrent.Futures
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import com.r3corda.core.crypto.generateKeyPair
import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.CityDatabase import com.r3corda.core.node.CityDatabase
import com.r3corda.core.node.PhysicalLocation import com.r3corda.core.node.PhysicalLocation
@ -73,8 +74,11 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair) return SimulatedNode(cfg, network, networkMapAddr, advertisedServices, id, keyPair)
} }
fun createAll(): List<SimulatedNode> = bankLocations. fun createAll(): List<SimulatedNode> {
map { network.createNode(networkMap.info.address, start = false, nodeFactory = this) as SimulatedNode } return bankLocations.map {
network.createNode(networkMap.info.address, start = false, nodeFactory = this, keyPair = generateKeyPair()) as SimulatedNode
}
}
} }
val bankFactory = BankFactory() val bankFactory = BankFactory()

View File

@ -82,7 +82,7 @@
"quantity": 1000000, "quantity": 1000000,
"token": "EUR" "token": "EUR"
}, },
"valuationDate": "Every Local Business Day", "valuationDateDescription": "Every Local Business Day",
"notificationTime": "2:00pm London", "notificationTime": "2:00pm London",
"resolutionTime": "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ", "resolutionTime": "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
"interestRate": { "interestRate": {

View File

@ -18,7 +18,7 @@ define([], () => {
rounding: { rounding: {
quantity: 1000000 quantity: 1000000
}, },
valuationDate: "Every Local Business Day", valuationDateDescription: "Every Local Business Day",
notificationTime: "2:00pm London", notificationTime: "2:00pm London",
resolutionTime: "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given", resolutionTime: "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given",
interestRate: { interestRate: {

View File

@ -23,7 +23,7 @@
</tr> </tr>
<tr class="center aligned"> <tr class="center aligned">
<td>Valuation Date</td> <td>Valuation Date</td>
<td>{{deal.common.valuationDate}}</td> <td>{{deal.common.valuationDateDescription}}</td>
</tr> </tr>
<tr class="center aligned"> <tr class="center aligned">
<td>Legal Document Hash</td> <td>Legal Document Hash</td>

View File

@ -82,7 +82,7 @@
"quantity": 1000000, "quantity": 1000000,
"token": "EUR" "token": "EUR"
}, },
"valuationDate": "Every Local Business Day", "valuationDateDescription": "Every Local Business Day",
"notificationTime": "2:00pm London", "notificationTime": "2:00pm London",
"resolutionTime": "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ", "resolutionTime": "2:00pm London time on the first LocalBusiness Day following the date on which the notice is given ",
"interestRate": { "interestRate": {