Moved Currency stuff in ContractsDSL out of core and into finance

This commit is contained in:
Shams Asari 2017-08-14 19:03:24 +01:00
parent f6e7814638
commit 62b26bcd89
65 changed files with 278 additions and 234 deletions

View File

@ -29,6 +29,7 @@ import net.corda.core.transactions.NotaryChangeWireTransaction
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.finance.parseCurrency
import net.i2p.crypto.eddsa.EdDSAPublicKey
import org.bouncycastle.asn1.x500.X500Name
import java.math.BigDecimal
@ -348,7 +349,7 @@ object JacksonSupport {
object AmountDeserializer : JsonDeserializer<Amount<*>>() {
override fun deserialize(parser: JsonParser, context: DeserializationContext): Amount<*> {
try {
return Amount.parseCurrency(parser.text)
return parseCurrency(parser.text)
} catch (e: Exception) {
try {
val tree = parser.readValueAsTree<JsonNode>()

View File

@ -2,12 +2,13 @@ package net.corda.jackson
import com.fasterxml.jackson.databind.SerializationFeature
import net.corda.core.contracts.Amount
import net.corda.core.contracts.USD
import net.corda.finance.USD
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.TransactionSignature
import net.corda.core.crypto.generateKeyPair
import net.corda.core.transactions.SignedTransaction
import net.corda.finance.parseCurrency
import net.corda.testing.ALICE_PUBKEY
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.MINI_CORP
@ -52,7 +53,7 @@ class JacksonSupportTest : TestDependencyInjectionBase() {
@Test
fun writeAmount() {
val writer = mapper.writer().without(SerializationFeature.INDENT_OUTPUT)
assertEquals("""{"notional":"25000000.00 USD"}""", writer.writeValueAsString(Dummy(Amount.parseCurrency("$25000000"))))
assertEquals("""{"notional":"25000000.00 USD"}""", writer.writeValueAsString(Dummy(parseCurrency("$25000000"))))
}
@Test

View File

@ -5,8 +5,8 @@ import net.corda.client.jfx.model.ProgressTrackingEvent
import net.corda.core.internal.bufferUntilSubscribed
import net.corda.core.contracts.Amount
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.USD
import net.corda.finance.DOLLARS
import net.corda.finance.USD
import net.corda.core.crypto.isFulfilledBy
import net.corda.core.crypto.keys
import net.corda.core.flows.FlowInitiator

View File

@ -1,8 +1,8 @@
package net.corda.client.mock
import net.corda.core.contracts.Amount
import net.corda.core.contracts.GBP
import net.corda.core.contracts.USD
import net.corda.finance.GBP
import net.corda.finance.USD
import net.corda.core.identity.Party
import net.corda.core.utilities.OpaqueBytes
import net.corda.flows.CashFlowCommand

View File

@ -1,7 +1,7 @@
package net.corda.client.rpc;
import net.corda.core.concurrent.CordaFuture;
import net.corda.client.rpc.internal.RPCClient;
import net.corda.core.concurrent.CordaFuture;
import net.corda.core.contracts.Amount;
import net.corda.core.messaging.CordaRPCOps;
import net.corda.core.messaging.FlowHandle;
@ -22,9 +22,13 @@ import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
import static kotlin.test.AssertionsKt.assertEquals;
import static net.corda.client.rpc.CordaRPCClientConfiguration.getDefault;
import static net.corda.contracts.GetBalances.getCashBalance;
import static net.corda.finance.CurrencyUtils.DOLLARS;
import static net.corda.node.services.RPCUserServiceKt.startFlowPermission;
import static net.corda.testing.TestConstants.getALICE;
@ -45,10 +49,10 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
@Before
public void setUp() throws ExecutionException, InterruptedException {
Set<ServiceInfo> services = new HashSet<>(Collections.singletonList(new ServiceInfo(ValidatingNotaryService.Companion.getType(), null)));
CordaFuture<Node> nodeFuture = startNode(getALICE().getName(), 1, services, Arrays.asList(rpcUser), Collections.emptyMap());
Set<ServiceInfo> services = new HashSet<>(singletonList(new ServiceInfo(ValidatingNotaryService.Companion.getType(), null)));
CordaFuture<Node> nodeFuture = startNode(getALICE().getName(), 1, services, singletonList(rpcUser), emptyMap());
node = nodeFuture.get();
client = new CordaRPCClient(node.getConfiguration().getRpcAddress(), null, getDefault(), false);
client = new CordaRPCClient(requireNonNull(node.getConfiguration().getRpcAddress()), null, getDefault(), false);
}
@After
@ -65,10 +69,8 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
public void testCashBalances() throws NoSuchFieldException, ExecutionException, InterruptedException {
login(rpcUser.getUsername(), rpcUser.getPassword());
Amount<Currency> dollars123 = new Amount<>(123, Currency.getInstance("USD"));
FlowHandle<AbstractCashFlow.Result> flowHandle = rpcProxy.startFlowDynamic(CashIssueFlow.class,
dollars123, OpaqueBytes.of("1".getBytes()),
DOLLARS(123), OpaqueBytes.of("1".getBytes()),
node.info.getLegalIdentity(), node.info.getLegalIdentity());
System.out.println("Started issuing cash, waiting on result");
flowHandle.getReturnValue().get();
@ -76,6 +78,6 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
Amount<Currency> balance = getCashBalance(rpcProxy, Currency.getInstance("USD"));
System.out.print("Balance: " + balance + "\n");
assertEquals(dollars123, balance, "matching");
assertEquals(DOLLARS(123), balance, "matching");
}
}

View File

@ -2,8 +2,8 @@ package net.corda.client.rpc
import net.corda.contracts.getCashBalance
import net.corda.contracts.getCashBalances
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.USD
import net.corda.finance.DOLLARS
import net.corda.finance.USD
import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowInitiator
import net.corda.core.messaging.*

View File

@ -7,7 +7,6 @@ import net.corda.client.rpc.notUsed
import net.corda.contracts.asset.Cash
import net.corda.contracts.getCashBalance
import net.corda.contracts.getCashBalances
import net.corda.core.contracts.*
import net.corda.core.crypto.SecureHash
import net.corda.core.internal.InputStreamAndHash
import net.corda.core.messaging.*
@ -18,6 +17,10 @@ import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.core.utilities.seconds
import net.corda.finance.DOLLARS
import net.corda.finance.POUNDS
import net.corda.finance.SWISS_FRANCS
import net.corda.finance.USD
import net.corda.flows.CashIssueFlow
import net.corda.flows.CashPaymentFlow
import net.corda.nodeapi.User

View File

@ -1,9 +1,9 @@
package net.corda.core.contracts
import net.corda.core.crypto.composite.CompositeKey
import net.corda.core.utilities.exactAdd
import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.exactAdd
import java.math.BigDecimal
import java.math.RoundingMode
import java.util.*
@ -85,66 +85,6 @@ data class Amount<T : Any>(val quantity: Long, val displayTokenSize: BigDecimal,
}
return BigDecimal.ONE
}
private val currencySymbols: Map<String, Currency> = mapOf(
"$" to USD,
"£" to GBP,
"" to EUR,
"¥" to JPY,
"" to RUB
)
private val currencyCodes: Map<String, Currency> by lazy { Currency.getAvailableCurrencies().map { it.currencyCode to it }.toMap() }
/**
* Returns an amount that is equal to the given currency amount in text. Examples of what is supported:
*
* - 12 USD
* - 14.50 USD
* - 10 USD
* - 30 CHF
* - $10.24
* - £13
* - 5000
*
* Note this method does NOT respect internationalisation rules: it ignores commas and uses . as the
* decimal point separator, always. It also ignores the users locale:
*
* - $ is always USD,
* - £ is always GBP
* - is always the Euro
* - ¥ is always Japanese Yen.
* - is always the Russian ruble.
*
* Thus an input of $12 expecting some other countries dollar will not work. Do your own parsing if
* you need correct handling of currency amounts with locale-sensitive handling.
*
* @throws IllegalArgumentException if the input string was not understood.
*/
fun parseCurrency(input: String): Amount<Currency> {
val i = input.filter { it != ',' }
try {
// First check the symbols at the front.
for ((symbol, currency) in currencySymbols) {
if (i.startsWith(symbol)) {
val rest = i.substring(symbol.length)
return fromDecimal(BigDecimal(rest), currency)
}
}
// Now check the codes at the end.
val split = i.split(' ')
if (split.size == 2) {
val (rest, code) = split
for ((cc, currency) in currencyCodes) {
if (cc == code) {
return fromDecimal(BigDecimal(rest), currency)
}
}
}
} catch(e: Exception) {
throw IllegalArgumentException("Could not parse $input as a currency", e)
}
throw IllegalArgumentException("Did not recognise the currency in $input or could not parse")
}
}
init {

View File

@ -4,7 +4,6 @@ package net.corda.core.contracts
import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party
import java.math.BigDecimal
import java.security.PublicKey
import java.util.*
@ -12,41 +11,10 @@ import java.util.*
* Defines a simple domain specific language for the specification of financial contracts. Currently covers:
*
* - Some utilities for working with commands.
* - Code for working with currencies.
* - An Amount type that represents a positive quantity of a specific currency.
* - An Amount type that represents a positive quantity of a specific token.
* - A simple language extension for specifying requirements in English, along with logic to enforce them.
*
* TODO: Look into replacing Currency and Amount with CurrencyUnit and MonetaryAmount from the javax.money API (JSR 354)
*/
//// Currencies ///////////////////////////////////////////////////////////////////////////////////////////////////////
fun currency(code: String) = Currency.getInstance(code)!!
@JvmField val USD = currency("USD")
@JvmField val GBP = currency("GBP")
@JvmField val EUR = currency("EUR")
@JvmField val CHF = currency("CHF")
@JvmField val JPY = currency("JPY")
@JvmField val RUB = currency("RUB")
fun <T : Any> AMOUNT(amount: Int, token: T): Amount<T> = Amount.fromDecimal(BigDecimal.valueOf(amount.toLong()), token)
fun <T : Any> AMOUNT(amount: Double, token: T): Amount<T> = Amount.fromDecimal(BigDecimal.valueOf(amount), token)
fun DOLLARS(amount: Int): Amount<Currency> = AMOUNT(amount, USD)
fun DOLLARS(amount: Double): Amount<Currency> = AMOUNT(amount, USD)
fun POUNDS(amount: Int): Amount<Currency> = AMOUNT(amount, GBP)
fun SWISS_FRANCS(amount: Int): Amount<Currency> = AMOUNT(amount, CHF)
val Int.DOLLARS: Amount<Currency> get() = DOLLARS(this)
val Double.DOLLARS: Amount<Currency> get() = DOLLARS(this)
val Int.POUNDS: Amount<Currency> get() = POUNDS(this)
val Int.SWISS_FRANCS: Amount<Currency> get() = SWISS_FRANCS(this)
infix fun Currency.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
infix fun Amount<Currency>.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
infix fun Currency.issuedBy(deposit: PartyAndReference) = Issued(deposit, this)
infix fun Amount<Currency>.issuedBy(deposit: PartyAndReference) = Amount(quantity, displayTokenSize, token.issuedBy(deposit))
//// Requirements /////////////////////////////////////////////////////////////////////////////////////////////////////
object Requirements {

View File

@ -43,31 +43,31 @@ inline fun Logger.debug(msg: () -> String) {
* Extension method for easier construction of [Duration]s in terms of integer days: `val twoDays = 2.days`.
* @see Duration.ofDays
*/
inline val Int.days: Duration get() = Duration.ofDays(toLong())
val Int.days: Duration get() = Duration.ofDays(toLong())
/**
* Extension method for easier construction of [Duration]s in terms of integer hours: `val twoHours = 2.hours`.
* @see Duration.ofHours
*/
inline val Int.hours: Duration get() = Duration.ofHours(toLong())
val Int.hours: Duration get() = Duration.ofHours(toLong())
/**
* Extension method for easier construction of [Duration]s in terms of integer minutes: `val twoMinutes = 2.minutes`.
* @see Duration.ofMinutes
*/
inline val Int.minutes: Duration get() = Duration.ofMinutes(toLong())
val Int.minutes: Duration get() = Duration.ofMinutes(toLong())
/**
* Extension method for easier construction of [Duration]s in terms of integer seconds: `val twoSeconds = 2.seconds`.
* @see Duration.ofSeconds
*/
inline val Int.seconds: Duration get() = Duration.ofSeconds(toLong())
val Int.seconds: Duration get() = Duration.ofSeconds(toLong())
/**
* Extension method for easier construction of [Duration]s in terms of integer milliseconds: `val twoMillis = 2.millis`.
* @see Duration.ofMillis
*/
inline val Int.millis: Duration get() = Duration.ofMillis(toLong())
val Int.millis: Duration get() = Duration.ofMillis(toLong())
/**
* A simple wrapper that enables the use of Kotlin's `val x by transient { ... }` syntax. Such a property

View File

@ -1,5 +1,6 @@
package net.corda.core.contracts
import net.corda.finance.*
import org.junit.Test
import java.math.BigDecimal
import java.util.*
@ -13,13 +14,6 @@ import kotlin.test.assertTrue
* Tests of the [Amount] class.
*/
class AmountTests {
@Test
fun basicCurrency() {
val expected = 1000L
val amount = Amount(expected, GBP)
assertEquals(expected, amount.quantity)
}
@Test
fun `make sure Amount has decimal places`() {
val x = Amount(1, Currency.getInstance("USD"))
@ -27,7 +21,7 @@ class AmountTests {
}
@Test
fun decimalConversion() {
fun `decimal conversion`() {
val quantity = 1234L
val amountGBP = Amount(quantity, GBP)
val expectedGBP = BigDecimal("12.34")
@ -49,22 +43,6 @@ class AmountTests {
override fun toString(): String = name
}
@Test
fun parsing() {
assertEquals(Amount(1234L, GBP), Amount.parseCurrency("£12.34"))
assertEquals(Amount(1200L, GBP), Amount.parseCurrency("£12"))
assertEquals(Amount(1000L, USD), Amount.parseCurrency("$10"))
assertEquals(Amount(5000L, JPY), Amount.parseCurrency("¥5000"))
assertEquals(Amount(500000L, RUB), Amount.parseCurrency("₽5000"))
assertEquals(Amount(1500000000L, CHF), Amount.parseCurrency("15,000,000 CHF"))
}
@Test
fun rendering() {
assertEquals("5000 JPY", Amount.parseCurrency("¥5000").toString())
assertEquals("50.12 USD", Amount.parseCurrency("$50.12").toString())
}
@Test
fun split() {
for (baseQuantity in 0..1000) {
@ -81,7 +59,7 @@ class AmountTests {
}
@Test
fun amountTransfersEquality() {
fun `amount transfers equality`() {
val partyA = "A"
val partyB = "B"
val partyC = "C"
@ -106,7 +84,7 @@ class AmountTests {
}
@Test
fun amountTransferAggregation() {
fun `amount transfer aggregation`() {
val partyA = "A"
val partyB = "B"
val partyC = "C"
@ -137,7 +115,7 @@ class AmountTests {
}
@Test
fun amountTransferApply() {
fun `amount transfer apply`() {
val partyA = "A"
val partyB = "B"
val partyC = "C"
@ -182,6 +160,5 @@ class AmountTests {
assertEquals(originalTotals[Pair(partyC, USD)], newTotals3[Pair(partyC, USD)])
assertEquals(originalTotals[Pair(partyA, GBP)], newTotals3[Pair(partyA, GBP)])
assertEquals(originalTotals[Pair(partyB, GBP)], newTotals3[Pair(partyB, GBP)])
}
}

View File

@ -4,6 +4,8 @@ import net.corda.contracts.asset.Cash
import net.corda.core.crypto.SecureHash
import net.corda.core.identity.AbstractParty
import net.corda.core.transactions.LedgerTransaction
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.testing.MEGA_CORP
import net.corda.testing.MINI_CORP
import net.corda.testing.ledger

View File

@ -8,6 +8,8 @@ import net.corda.core.identity.Party
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.core.transactions.WireTransaction
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.testing.*
import org.junit.Test
import java.security.PublicKey

View File

@ -14,6 +14,8 @@ import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.SignedTransaction
import net.corda.core.internal.Emoji
import net.corda.core.utilities.getOrThrow
import net.corda.finance.USD
import net.corda.finance.`issued by`
import net.corda.flows.CashIssueFlow
import net.corda.node.internal.CordaRPCOpsImpl
import net.corda.node.services.startFlowPermission

View File

@ -2,7 +2,7 @@ package net.corda.core.flows
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount
import net.corda.core.contracts.GBP
import net.corda.finance.GBP
import net.corda.core.contracts.Issued
import net.corda.core.identity.Party
import net.corda.core.transactions.TransactionBuilder

View File

@ -2,7 +2,7 @@ package net.corda.core.flows
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount
import net.corda.core.contracts.GBP
import net.corda.finance.GBP
import net.corda.core.contracts.Issued
import net.corda.core.identity.Party
import net.corda.core.transactions.TransactionBuilder

View File

@ -6,6 +6,7 @@ import net.corda.core.identity.AbstractParty
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds
import net.corda.finance.POUNDS
import net.corda.testing.*
import net.corda.testing.node.MockServices
import org.junit.Before

View File

@ -40,6 +40,8 @@ UNRELEASED
If you specifically need well known identities, use the network map, which is the authoritative source of current well
known identities.
* Currency-related API in ``net.corda.core.contracts.ContractsDSL`` has moved to ```net.corda.finance.CurrencyUtils`.
Milestone 14
------------

View File

@ -2,13 +2,12 @@ package net.corda.docs
import net.corda.contracts.asset.Cash
import net.corda.core.concurrent.CordaFuture
import net.corda.core.contracts.DOLLARS
import net.corda.finance.DOLLARS
import net.corda.core.internal.concurrent.transpose
import net.corda.core.messaging.startFlow
import net.corda.core.messaging.vaultTrackBy
import net.corda.core.node.services.ServiceInfo
import net.corda.core.node.services.Vault
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.flows.CashIssueFlow

View File

@ -3,7 +3,7 @@ package net.corda.docs
import net.corda.client.rpc.notUsed
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount
import net.corda.core.contracts.USD
import net.corda.finance.USD
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.core.messaging.vaultQueryBy

View File

@ -5,6 +5,7 @@ import net.corda.core.contracts.*
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.*
import net.corda.flows.CashIssueFlow
import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.ValidatingNotaryService

View File

@ -1,11 +1,11 @@
package net.corda.docs
import net.corda.contracts.getCashBalances
import net.corda.core.contracts.*
import net.corda.core.node.services.ServiceInfo
import net.corda.core.toFuture
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.*
import net.corda.flows.CashIssueFlow
import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.ValidatingNotaryService

View File

@ -1,6 +1,6 @@
package net.corda.contracts.universal
import net.corda.core.contracts.USD
import net.corda.finance.USD
import org.junit.Ignore
import org.junit.Test

View File

@ -0,0 +1,96 @@
@file:JvmName("CurrencyUtils")
package net.corda.finance
import net.corda.core.contracts.Amount
import net.corda.core.contracts.Issued
import net.corda.core.contracts.PartyAndReference
import java.math.BigDecimal
import java.util.*
@JvmField val USD: Currency = Currency.getInstance("USD")
@JvmField val GBP: Currency = Currency.getInstance("GBP")
@JvmField val EUR: Currency = Currency.getInstance("EUR")
@JvmField val CHF: Currency = Currency.getInstance("CHF")
@JvmField val JPY: Currency = Currency.getInstance("JPY")
@JvmField val RUB: Currency = Currency.getInstance("RUB")
fun <T : Any> AMOUNT(amount: Int, token: T): Amount<T> = Amount.fromDecimal(BigDecimal.valueOf(amount.toLong()), token)
fun <T : Any> AMOUNT(amount: Double, token: T): Amount<T> = Amount.fromDecimal(BigDecimal.valueOf(amount), token)
fun DOLLARS(amount: Int): Amount<Currency> = AMOUNT(amount, USD)
fun DOLLARS(amount: Double): Amount<Currency> = AMOUNT(amount, USD)
fun POUNDS(amount: Int): Amount<Currency> = AMOUNT(amount, GBP)
fun SWISS_FRANCS(amount: Int): Amount<Currency> = AMOUNT(amount, CHF)
val Int.DOLLARS: Amount<Currency> get() = DOLLARS(this)
val Double.DOLLARS: Amount<Currency> get() = DOLLARS(this)
val Int.POUNDS: Amount<Currency> get() = POUNDS(this)
val Int.SWISS_FRANCS: Amount<Currency> get() = SWISS_FRANCS(this)
infix fun Currency.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
infix fun Amount<Currency>.`issued by`(deposit: PartyAndReference) = issuedBy(deposit)
infix fun Currency.issuedBy(deposit: PartyAndReference) = Issued(deposit, this)
infix fun Amount<Currency>.issuedBy(deposit: PartyAndReference) = Amount(quantity, displayTokenSize, token.issuedBy(deposit))
private val currencySymbols: Map<String, Currency> = mapOf(
"$" to USD,
"£" to GBP,
"" to EUR,
"¥" to JPY,
"" to RUB
)
private val currencyCodes: Map<String, Currency> by lazy {
Currency.getAvailableCurrencies().associateBy { it.currencyCode }
}
/**
* Returns an amount that is equal to the given currency amount in text. Examples of what is supported:
*
* - 12 USD
* - 14.50 USD
* - 10 USD
* - 30 CHF
* - $10.24
* - £13
* - 5000
*
* Note this method does NOT respect internationalisation rules: it ignores commas and uses . as the
* decimal point separator, always. It also ignores the users locale:
*
* - $ is always USD,
* - £ is always GBP
* - is always the Euro
* - ¥ is always Japanese Yen.
* - is always the Russian ruble.
*
* Thus an input of $12 expecting some other countries dollar will not work. Do your own parsing if
* you need correct handling of currency amounts with locale-sensitive handling.
*
* @throws IllegalArgumentException if the input string was not understood.
*/
fun parseCurrency(input: String): Amount<Currency> {
val i = input.filter { it != ',' }
try {
// First check the symbols at the front.
for ((symbol, currency) in currencySymbols) {
if (i.startsWith(symbol)) {
val rest = i.substring(symbol.length)
return Amount.fromDecimal(BigDecimal(rest), currency)
}
}
// Now check the codes at the end.
val split = i.split(' ')
if (split.size == 2) {
val (rest, code) = split
for ((cc, currency) in currencyCodes) {
if (cc == code) {
return Amount.fromDecimal(BigDecimal(rest), currency)
}
}
}
} catch(e: Exception) {
throw IllegalArgumentException("Could not parse $input as a currency", e)
}
throw IllegalArgumentException("Did not recognise the currency in $input or could not parse")
}

View File

@ -4,7 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount
import net.corda.core.contracts.InsufficientBalanceException
import net.corda.core.contracts.issuedBy
import net.corda.finance.issuedBy
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import net.corda.core.node.services.queryBy

View File

@ -3,7 +3,7 @@ package net.corda.flows
import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount
import net.corda.core.contracts.issuedBy
import net.corda.finance.issuedBy
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.flows.TransactionKeyFlow

View File

@ -2,7 +2,9 @@ package net.corda.flows
import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.*
import net.corda.core.contracts.Amount
import net.corda.core.contracts.FungibleAsset
import net.corda.core.contracts.Issued
import net.corda.core.flows.*
import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable
@ -10,6 +12,10 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap
import net.corda.finance.CHF
import net.corda.finance.EUR
import net.corda.finance.GBP
import net.corda.finance.USD
import java.util.*
/**

View File

@ -6,8 +6,8 @@ import net.corda.core.identity.AnonymousParty;
import net.corda.core.utilities.OpaqueBytes;
import org.junit.Test;
import static net.corda.core.contracts.ContractsDSL.DOLLARS;
import static net.corda.core.contracts.ContractsDSL.issuedBy;
import static net.corda.finance.CurrencyUtils.DOLLARS;
import static net.corda.finance.CurrencyUtils.issuedBy;
import static net.corda.testing.CoreTestUtils.*;
/**

View File

@ -10,6 +10,8 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.days
import net.corda.core.utilities.seconds
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash
import net.corda.testing.node.MockServices

View File

@ -11,6 +11,7 @@ import net.corda.core.node.services.queryBy
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.finance.*
import net.corda.node.services.vault.NodeVaultService
import net.corda.node.utilities.CordaPersistence
import net.corda.testing.*

View File

@ -13,6 +13,7 @@ import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.days
import net.corda.core.utilities.hours
import net.corda.finance.*
import net.corda.testing.*
import net.corda.testing.contracts.DummyState
import net.corda.testing.node.MockServices

View File

@ -0,0 +1,30 @@
package net.corda.finance
import net.corda.core.contracts.*
import org.junit.Test
import kotlin.test.assertEquals
class CurrencyUtilsTest {
@Test
fun `basic currency`() {
val expected = 1000L
val amount = Amount(expected, GBP)
assertEquals(expected, amount.quantity)
}
@Test
fun parseCurrency() {
assertEquals(Amount(1234L, GBP), parseCurrency("£12.34"))
assertEquals(Amount(1200L, GBP), parseCurrency("£12"))
assertEquals(Amount(1000L, USD), parseCurrency("$10"))
assertEquals(Amount(5000L, JPY), parseCurrency("¥5000"))
assertEquals(Amount(500000L, RUB), parseCurrency("₽5000"))
assertEquals(Amount(1500000000L, CHF), parseCurrency("15,000,000 CHF"))
}
@Test
fun rendering() {
assertEquals("5000 JPY", parseCurrency("¥5000").toString())
assertEquals("50.12 USD", parseCurrency("$50.12").toString())
}
}

View File

@ -1,8 +1,8 @@
package net.corda.flows
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.`issued by`
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.core.identity.Party
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow

View File

@ -1,8 +1,8 @@
package net.corda.flows
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.`issued by`
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.core.identity.Party
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow

View File

@ -1,8 +1,8 @@
package net.corda.flows
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.`issued by`
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.core.identity.Party
import net.corda.core.node.services.Vault
import net.corda.core.node.services.trackBy

View File

@ -2,19 +2,18 @@ package net.corda.flows
import net.corda.contracts.asset.Cash
import net.corda.core.concurrent.CordaFuture
import net.corda.testing.contracts.calculateRandomlySizedAmounts
import net.corda.core.contracts.Amount
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.currency
import net.corda.core.flows.FlowException
import net.corda.core.identity.Party
import net.corda.core.node.services.Vault
import net.corda.core.node.services.trackBy
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS
import net.corda.flows.IssuerFlow.IssuanceRequester
import net.corda.testing.contracts.calculateRandomlySizedAmounts
import net.corda.testing.expect
import net.corda.testing.expectEvents
import net.corda.testing.node.MockNetwork
@ -109,7 +108,7 @@ class IssuerFlowTest(val anonymous: Boolean) {
val notary = notaryNode.services.myInfo.notaryIdentity
// try to issue an amount of a restricted currency
assertFailsWith<FlowException> {
runIssuerAndIssueRequester(bankOfCordaNode, bankClientNode, Amount(100000L, currency("BRL")),
runIssuerAndIssueRequester(bankOfCordaNode, bankClientNode, Amount(100000L, Currency.getInstance("BRL")),
bankClientNode.info.legalIdentity, OpaqueBytes.of(123), notary).getOrThrow()
}
}

View File

@ -2,7 +2,7 @@ package net.corda.node
import co.paralleluniverse.fibers.Suspendable
import com.google.common.base.Stopwatch
import net.corda.core.contracts.DOLLARS
import net.corda.finance.DOLLARS
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.concurrent.transpose

View File

@ -1,7 +1,7 @@
package net.corda.node.services
import net.corda.core.contracts.Amount
import net.corda.core.contracts.POUNDS
import net.corda.finance.POUNDS
import net.corda.core.identity.Party
import net.corda.core.internal.bufferUntilSubscribed
import net.corda.core.messaging.CordaRPCOps

View File

@ -14,6 +14,9 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.getOrThrow
import net.corda.core.node.services.queryBy
import net.corda.core.utilities.OpaqueBytes
import net.corda.finance.DOLLARS
import net.corda.finance.GBP
import net.corda.finance.USD
import net.corda.flows.CashIssueFlow
import net.corda.flows.CashPaymentFlow
import net.corda.node.internal.CordaRPCOpsImpl

View File

@ -33,6 +33,8 @@ import net.corda.core.utilities.days
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.toNonEmptySet
import net.corda.core.utilities.unwrap
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.flows.TwoPartyTradeFlow.Buyer
import net.corda.flows.TwoPartyTradeFlow.Seller
import net.corda.node.internal.AbstractNode

View File

@ -10,6 +10,9 @@ import net.corda.core.schemas.CommonSchemaV1
import net.corda.core.schemas.PersistentStateRef
import net.corda.core.serialization.deserialize
import net.corda.core.transactions.SignedTransaction
import net.corda.finance.DOLLARS
import net.corda.finance.POUNDS
import net.corda.finance.SWISS_FRANCS
import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.vault.VaultSchemaV1

View File

@ -4,7 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount
import net.corda.core.contracts.Issued
import net.corda.core.contracts.USD
import net.corda.finance.USD
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow

View File

@ -5,7 +5,7 @@ import co.paralleluniverse.fibers.Suspendable
import co.paralleluniverse.strands.concurrent.Semaphore
import net.corda.core.concurrent.CordaFuture
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.DOLLARS
import net.corda.finance.DOLLARS
import net.corda.core.contracts.StateAndRef
import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.random63BitValue

View File

@ -20,6 +20,7 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.NonEmptySet
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.toNonEmptySet
import net.corda.finance.*
import net.corda.node.utilities.CordaPersistence
import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash

View File

@ -15,6 +15,7 @@ import net.corda.core.node.services.*
import net.corda.core.node.services.vault.*
import net.corda.core.node.services.vault.QueryCriteria.*
import net.corda.core.utilities.*
import net.corda.finance.*
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.schemas.CashSchemaV1

View File

@ -4,7 +4,9 @@ import net.corda.contracts.asset.Cash
import net.corda.contracts.asset.DUMMY_CASH_ISSUER
import net.corda.contracts.asset.DUMMY_CASH_ISSUER_KEY
import net.corda.contracts.getCashBalance
import net.corda.core.contracts.*
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.LinearState
import net.corda.core.contracts.UniqueIdentifier
import net.corda.core.identity.AnonymousParty
import net.corda.core.node.services.Vault
import net.corda.core.node.services.VaultQueryService
@ -13,6 +15,7 @@ import net.corda.core.node.services.queryBy
import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
import net.corda.core.transactions.TransactionBuilder
import net.corda.finance.*
import net.corda.node.utilities.CordaPersistence
import net.corda.testing.*
import net.corda.testing.contracts.*

View File

@ -1,9 +1,8 @@
package net.corda.bank
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.DOLLARS
import net.corda.finance.DOLLARS
import net.corda.core.messaging.startFlow
import net.corda.core.messaging.vaultTrackBy
import net.corda.core.node.services.ServiceInfo
import net.corda.core.node.services.Vault
import net.corda.core.node.services.vault.QueryCriteria

View File

@ -3,15 +3,14 @@ package net.corda.bank.api
import net.corda.bank.api.BankOfCordaWebApi.IssueRequestParams
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.Amount
import net.corda.core.contracts.currency
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.flows.IssuerFlow.IssuanceRequester
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.http.HttpApi
import java.util.*
/**
* Interface for communicating with Bank of Corda node
@ -46,7 +45,7 @@ class BankOfCordaClientApi(val hostAndPort: NetworkHostAndPort) {
val notaryNode = rpc.nodeIdentityFromParty(notaryLegalIdentity)
?: throw IllegalStateException("Unable to locate notary node in network map cache")
val amount = Amount(params.amount, currency(params.currency))
val amount = Amount(params.amount, Currency.getInstance(params.currency))
val issuerToPartyRef = OpaqueBytes.of(params.issueToPartyRefAsString.toByte())
return rpc.startFlow(::IssuanceRequester, amount, issueToParty, issuerToPartyRef, issuerBankParty, notaryNode.notaryIdentity, params.anonymous)

View File

@ -1,7 +1,6 @@
package net.corda.bank.api
import net.corda.core.contracts.Amount
import net.corda.core.contracts.currency
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.core.utilities.OpaqueBytes
@ -10,6 +9,7 @@ import net.corda.core.utilities.loggerFor
import net.corda.flows.IssuerFlow.IssuanceRequester
import org.bouncycastle.asn1.x500.X500Name
import java.time.LocalDateTime
import java.util.*
import javax.ws.rs.*
import javax.ws.rs.core.MediaType
import javax.ws.rs.core.Response
@ -49,9 +49,9 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
val notaryParty = rpc.partyFromX500Name(params.notaryName)
?: return Response.status(Response.Status.FORBIDDEN).entity("Unable to locate ${params.notaryName} in identity service").build()
val notaryNode = rpc.nodeIdentityFromParty(notaryParty)
?: return Response.status(Response.Status.FORBIDDEN).entity("Unable to locate ${notaryParty} in network map service").build()
?: return Response.status(Response.Status.FORBIDDEN).entity("Unable to locate $notaryParty in network map service").build()
val amount = Amount(params.amount, currency(params.currency))
val amount = Amount(params.amount, Currency.getInstance(params.currency))
val issuerToPartyRef = OpaqueBytes.of(params.issueToPartyRefAsString.toByte())
val anonymous = params.anonymous
@ -62,7 +62,7 @@ class BankOfCordaWebApi(val rpc: CordaRPCOps) {
logger.info("Issue request completed successfully: $params")
Response.status(Response.Status.CREATED).build()
} catch (e: Exception) {
logger.error("Issue request failed: ${e}", e)
logger.error("Issue request failed", e)
Response.status(Response.Status.FORBIDDEN).build()
}
}

View File

@ -14,6 +14,7 @@ import net.corda.core.node.services.ServiceInfo
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS
import net.corda.irs.flows.RatesFixFlow
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase

View File

@ -1,10 +1,13 @@
package net.corda.irs.contract
import net.corda.contracts.*
import net.corda.core.contracts.*
import net.corda.core.contracts.Amount
import net.corda.core.contracts.UniqueIdentifier
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds
import net.corda.finance.DOLLARS
import net.corda.finance.EUR
import net.corda.testing.*
import net.corda.testing.node.MockServices
import org.junit.Test
@ -79,8 +82,6 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
fixedLegPaymentSchedule = mutableMapOf()
)
val EUR = currency("EUR")
val common = InterestRateSwap.Common(
baseCurrency = EUR,
eligibleCurrency = EUR,
@ -169,8 +170,6 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
fixedLegPaymentSchedule = mutableMapOf()
)
val EUR = currency("EUR")
val common = InterestRateSwap.Common(
baseCurrency = EUR,
eligibleCurrency = EUR,

View File

@ -11,6 +11,7 @@ import net.corda.core.identity.Party
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.finance.GBP
@StartableByRPC
class DummyIssueAndMove(private val notary: Party, private val counterpartyNode: Party, private val discriminator: Int) : FlowLogic<SignedTransaction>() {

View File

@ -1,20 +1,19 @@
package net.corda.traderdemo
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.DOLLARS
import net.corda.core.utilities.millis
import net.corda.core.node.services.ServiceInfo
import net.corda.core.internal.concurrent.transpose
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.millis
import net.corda.finance.DOLLARS
import net.corda.flows.CashIssueFlow
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
import net.corda.flows.IssuerFlow
import net.corda.node.services.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.BOC
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.driver.poll
import net.corda.testing.node.NodeBasedTest
import net.corda.traderdemo.flow.BuyerFlow
@ -30,7 +29,7 @@ class TraderDemoTest : NodeBasedTest() {
val demoUser = User("demo", "demo", setOf(startFlowPermission<SellerFlow>()))
val bankUser = User("user1", "test", permissions = setOf(startFlowPermission<CashIssueFlow>(),
startFlowPermission<CommercialPaperIssueFlow>()))
val (nodeA, nodeB, bankNode, notaryNode) = listOf(
val (nodeA, nodeB, bankNode) = listOf(
startNode(DUMMY_BANK_A.name, rpcUsers = listOf(demoUser)),
startNode(DUMMY_BANK_B.name, rpcUsers = listOf(demoUser)),
startNode(BOC.name, rpcUsers = listOf(bankUser)),
@ -57,7 +56,7 @@ class TraderDemoTest : NodeBasedTest() {
val expectedPaper = listOf(clientA.commercialPaperCount + 1, clientB.commercialPaperCount)
// TODO: Enable anonymisation
clientBank.runIssuer(amount = 100.DOLLARS, buyerName = nodeA.info.legalIdentity.name, sellerName = nodeB.info.legalIdentity.name, notaryName = notaryNode.info.legalIdentity.name)
clientBank.runIssuer(amount = 100.DOLLARS, buyerName = nodeA.info.legalIdentity.name, sellerName = nodeB.info.legalIdentity.name)
clientB.runSeller(buyerName = nodeA.info.legalIdentity.name, amount = 5.DOLLARS)
assertThat(clientA.cashCount).isGreaterThan(originalACash)

View File

@ -2,12 +2,11 @@ package net.corda.traderdemo
import joptsimple.OptionParser
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.DOLLARS
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.loggerFor
import net.corda.finance.DOLLARS
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
import org.slf4j.Logger
import kotlin.system.exitProcess
@ -28,8 +27,6 @@ private class TraderDemo {
val logger: Logger = loggerFor<TraderDemo>()
val buyerName = DUMMY_BANK_A.name
val sellerName = DUMMY_BANK_B.name
val notaryName = DUMMY_NOTARY.name
val buyerRpcPort = 10006
val sellerRpcPort = 10009
val bankRpcPort = 10012
}
@ -52,7 +49,7 @@ private class TraderDemo {
if (role == Role.BANK) {
val bankHost = NetworkHostAndPort("localhost", bankRpcPort)
CordaRPCClient(bankHost).use("demo", "demo") {
TraderDemoClientApi(it.proxy).runIssuer(1100.DOLLARS, buyerName, sellerName, notaryName)
TraderDemoClientApi(it.proxy).runIssuer(1100.DOLLARS, buyerName, sellerName)
}
} else {
val sellerHost = NetworkHostAndPort("localhost", sellerRpcPort)

View File

@ -4,8 +4,6 @@ import net.corda.contracts.CommercialPaper
import net.corda.contracts.asset.Cash
import net.corda.contracts.getCashBalance
import net.corda.core.contracts.Amount
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.USD
import net.corda.core.internal.Emoji
import net.corda.core.internal.concurrent.transpose
import net.corda.core.messaging.CordaRPCOps
@ -15,7 +13,8 @@ import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.node.services.vault.builder
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.finance.DOLLARS
import net.corda.finance.USD
import net.corda.flows.CashIssueFlow
import net.corda.node.services.vault.VaultSchemaV1
import net.corda.testing.DUMMY_NOTARY
@ -29,10 +28,6 @@ import java.util.*
* Interface for communicating with nodes running the trader demo.
*/
class TraderDemoClientApi(val rpc: CordaRPCOps) {
private companion object {
val logger = loggerFor<TraderDemoClientApi>()
}
val cashCount: Long get() {
val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() }
val countCriteria = QueryCriteria.VaultCustomQueryCriteria(count)
@ -47,7 +42,7 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
return rpc.vaultQueryBy<CommercialPaper.State>(countCriteria).otherResults.single() as Long
}
fun runIssuer(amount: Amount<Currency> = 1100.0.DOLLARS, buyerName: X500Name, sellerName: X500Name, notaryName: X500Name) {
fun runIssuer(amount: Amount<Currency>, buyerName: X500Name, sellerName: X500Name) {
val ref = OpaqueBytes.of(1)
val buyer = rpc.partyFromX500Name(buyerName) ?: throw IllegalStateException("Don't know $buyerName")
val seller = rpc.partyFromX500Name(sellerName) ?: throw IllegalStateException("Don't know $sellerName")
@ -77,7 +72,7 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
}
// The line below blocks and waits for the future to resolve.
val stx = rpc.startFlow(::CommercialPaperIssueFlow, amount, ref, seller, notaryNode.notaryIdentity).returnValue.getOrThrow()
rpc.startFlow(::CommercialPaperIssueFlow, amount, ref, seller, notaryNode.notaryIdentity).returnValue.getOrThrow()
println("Commercial paper issued to seller")
}

View File

@ -2,16 +2,14 @@ package net.corda.traderdemo.flow
import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.CommercialPaper
import net.corda.contracts.asset.DUMMY_CASH_ISSUER
import net.corda.core.contracts.Amount
import net.corda.core.contracts.`issued by`
import net.corda.finance.`issued by`
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes

View File

@ -8,8 +8,8 @@ import net.corda.client.mock.pickOne
import net.corda.client.rpc.CordaRPCConnection
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount
import net.corda.core.contracts.GBP
import net.corda.core.contracts.USD
import net.corda.finance.GBP
import net.corda.finance.USD
import net.corda.core.identity.Party
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.messaging.CordaRPCOps

View File

@ -6,9 +6,9 @@ import net.corda.client.jfx.model.observableList
import net.corda.client.jfx.model.observableValue
import net.corda.client.jfx.utils.ChosenList
import net.corda.client.jfx.utils.map
import net.corda.core.contracts.currency
import net.corda.core.node.NodeInfo
import tornadofx.*
import java.util.*
val ISSUER_SERVICE_TYPE = Regex("corda.issuer.(USD|GBP|CHF|EUR)")
@ -34,7 +34,7 @@ class IssuerModel {
private fun NodeInfo.issuerCurrency() = if (isIssuerNode()) {
val issuer = advertisedServices.first { it.info.type.id.matches(ISSUER_SERVICE_TYPE) }
currency(issuer.info.type.id.substringAfterLast("."))
Currency.getInstance(issuer.info.type.id.substringAfterLast("."))
} else
null
}

View File

@ -6,6 +6,10 @@ import net.corda.client.jfx.model.ExchangeRateModel
import net.corda.client.jfx.model.observableValue
import net.corda.client.jfx.utils.AmountBindings
import net.corda.core.contracts.*
import net.corda.finance.CHF
import net.corda.finance.EUR
import net.corda.finance.GBP
import net.corda.finance.USD
import org.fxmisc.easybind.EasyBind
import tornadofx.*
import java.util.*

View File

@ -4,7 +4,6 @@ import javafx.beans.InvalidationListener
import javafx.beans.Observable
import javafx.beans.property.ObjectProperty
import javafx.beans.property.SimpleObjectProperty
import net.corda.core.contracts.currency
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.internal.exists
@ -59,7 +58,7 @@ class SettingsModel(path: Path = Paths.get("conf")) : Component(), Observable {
String::class.java -> string(metadata.name, "") as T
Int::class.java -> string(metadata.name, "0").toInt() as T
Boolean::class.java -> boolean(metadata.name) as T
Currency::class.java -> currency(string(metadata.name, "USD")) as T
Currency::class.java -> Currency.getInstance(string(metadata.name, "USD")) as T
Path::class.java -> Paths.get(string(metadata.name, "")).toAbsolutePath() as T
else -> throw IllegalArgumentException("Unsupported type ${metadata.returnType}")
}

View File

@ -1,23 +1,27 @@
package net.corda.explorer.model
import net.corda.core.contracts.USD
import net.corda.core.contracts.currency
import net.corda.finance.USD
import org.junit.Test
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class IssuerModelTest {
@Test
fun `test issuer regex`() {
val regex = Regex("corda.issuer.(USD|GBP|CHF)")
kotlin.test.assertTrue("corda.issuer.USD".matches(regex))
kotlin.test.assertTrue("corda.issuer.GBP".matches(regex))
assertTrue("corda.issuer.USD".matches(regex))
assertTrue("corda.issuer.GBP".matches(regex))
kotlin.test.assertFalse("corda.issuer.USD.GBP".matches(regex))
kotlin.test.assertFalse("corda.issuer.EUR".matches(regex))
kotlin.test.assertFalse("corda.issuer".matches(regex))
assertFalse("corda.issuer.USD.GBP".matches(regex))
assertFalse("corda.issuer.EUR".matches(regex))
assertFalse("corda.issuer".matches(regex))
kotlin.test.assertEquals(USD, currency("corda.issuer.USD".substringAfterLast(".")))
assertFailsWith(IllegalArgumentException::class, { currency("corda.issuer.DOLLAR".substringBeforeLast(".")) })
assertEquals(USD, Currency.getInstance("corda.issuer.USD".substringAfterLast(".")))
assertFailsWith(IllegalArgumentException::class) {
Currency.getInstance("corda.issuer.DOLLAR".substringBeforeLast("."))
}
}
}

View File

@ -5,7 +5,7 @@ import net.corda.client.mock.pickN
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Issued
import net.corda.core.contracts.PartyAndReference
import net.corda.core.contracts.USD
import net.corda.finance.USD
import net.corda.core.identity.AbstractParty
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.messaging.vaultQueryBy

View File

@ -5,7 +5,7 @@ import net.corda.client.mock.Generator
import net.corda.client.mock.pickOne
import net.corda.client.mock.replicatePoisson
import net.corda.contracts.asset.Cash
import net.corda.core.contracts.USD
import net.corda.finance.USD
import net.corda.core.flows.FlowException
import net.corda.core.identity.AbstractParty
import net.corda.core.utilities.getOrThrow

View File

@ -2,7 +2,7 @@ package net.corda.loadtest.tests
import net.corda.client.mock.Generator
import net.corda.core.contracts.Amount
import net.corda.core.contracts.USD
import net.corda.finance.USD
import net.corda.core.flows.FlowException
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.utilities.OpaqueBytes

View File

@ -1,7 +1,7 @@
package net.corda.verifier
import net.corda.client.mock.generateOrFail
import net.corda.core.contracts.DOLLARS
import net.corda.finance.DOLLARS
import net.corda.core.messaging.startFlow
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.OpaqueBytes