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

View File

@ -2,12 +2,13 @@ package net.corda.jackson
import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.databind.SerializationFeature
import net.corda.core.contracts.Amount 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.Crypto
import net.corda.core.crypto.SignatureMetadata import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.TransactionSignature import net.corda.core.crypto.TransactionSignature
import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.generateKeyPair
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.finance.parseCurrency
import net.corda.testing.ALICE_PUBKEY import net.corda.testing.ALICE_PUBKEY
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.MINI_CORP import net.corda.testing.MINI_CORP
@ -52,7 +53,7 @@ class JacksonSupportTest : TestDependencyInjectionBase() {
@Test @Test
fun writeAmount() { fun writeAmount() {
val writer = mapper.writer().without(SerializationFeature.INDENT_OUTPUT) 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 @Test

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
package net.corda.core.contracts package net.corda.core.contracts
import net.corda.core.crypto.composite.CompositeKey import net.corda.core.crypto.composite.CompositeKey
import net.corda.core.utilities.exactAdd
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.exactAdd
import java.math.BigDecimal import java.math.BigDecimal
import java.math.RoundingMode import java.math.RoundingMode
import java.util.* import java.util.*
@ -85,66 +85,6 @@ data class Amount<T : Any>(val quantity: Long, val displayTokenSize: BigDecimal,
} }
return BigDecimal.ONE 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 { init {

View File

@ -4,7 +4,6 @@ package net.corda.core.contracts
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
import java.math.BigDecimal
import java.security.PublicKey import java.security.PublicKey
import java.util.* import java.util.*
@ -12,41 +11,10 @@ import java.util.*
* Defines a simple domain specific language for the specification of financial contracts. Currently covers: * Defines a simple domain specific language for the specification of financial contracts. Currently covers:
* *
* - Some utilities for working with commands. * - Some utilities for working with commands.
* - Code for working with currencies. * - An Amount type that represents a positive quantity of a specific token.
* - An Amount type that represents a positive quantity of a specific currency.
* - A simple language extension for specifying requirements in English, along with logic to enforce them. * - 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 ///////////////////////////////////////////////////////////////////////////////////////////////////// //// Requirements /////////////////////////////////////////////////////////////////////////////////////////////////////
object 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`. * Extension method for easier construction of [Duration]s in terms of integer days: `val twoDays = 2.days`.
* @see Duration.ofDays * @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`. * Extension method for easier construction of [Duration]s in terms of integer hours: `val twoHours = 2.hours`.
* @see Duration.ofHours * @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`. * Extension method for easier construction of [Duration]s in terms of integer minutes: `val twoMinutes = 2.minutes`.
* @see Duration.ofMinutes * @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`. * Extension method for easier construction of [Duration]s in terms of integer seconds: `val twoSeconds = 2.seconds`.
* @see Duration.ofSeconds * @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`. * Extension method for easier construction of [Duration]s in terms of integer milliseconds: `val twoMillis = 2.millis`.
* @see Duration.ofMillis * @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 * 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 package net.corda.core.contracts
import net.corda.finance.*
import org.junit.Test import org.junit.Test
import java.math.BigDecimal import java.math.BigDecimal
import java.util.* import java.util.*
@ -13,13 +14,6 @@ import kotlin.test.assertTrue
* Tests of the [Amount] class. * Tests of the [Amount] class.
*/ */
class AmountTests { class AmountTests {
@Test
fun basicCurrency() {
val expected = 1000L
val amount = Amount(expected, GBP)
assertEquals(expected, amount.quantity)
}
@Test @Test
fun `make sure Amount has decimal places`() { fun `make sure Amount has decimal places`() {
val x = Amount(1, Currency.getInstance("USD")) val x = Amount(1, Currency.getInstance("USD"))
@ -27,7 +21,7 @@ class AmountTests {
} }
@Test @Test
fun decimalConversion() { fun `decimal conversion`() {
val quantity = 1234L val quantity = 1234L
val amountGBP = Amount(quantity, GBP) val amountGBP = Amount(quantity, GBP)
val expectedGBP = BigDecimal("12.34") val expectedGBP = BigDecimal("12.34")
@ -49,22 +43,6 @@ class AmountTests {
override fun toString(): String = name 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 @Test
fun split() { fun split() {
for (baseQuantity in 0..1000) { for (baseQuantity in 0..1000) {
@ -81,7 +59,7 @@ class AmountTests {
} }
@Test @Test
fun amountTransfersEquality() { fun `amount transfers equality`() {
val partyA = "A" val partyA = "A"
val partyB = "B" val partyB = "B"
val partyC = "C" val partyC = "C"
@ -106,7 +84,7 @@ class AmountTests {
} }
@Test @Test
fun amountTransferAggregation() { fun `amount transfer aggregation`() {
val partyA = "A" val partyA = "A"
val partyB = "B" val partyB = "B"
val partyC = "C" val partyC = "C"
@ -137,7 +115,7 @@ class AmountTests {
} }
@Test @Test
fun amountTransferApply() { fun `amount transfer apply`() {
val partyA = "A" val partyA = "A"
val partyB = "B" val partyB = "B"
val partyC = "C" val partyC = "C"
@ -182,6 +160,5 @@ class AmountTests {
assertEquals(originalTotals[Pair(partyC, USD)], newTotals3[Pair(partyC, USD)]) assertEquals(originalTotals[Pair(partyC, USD)], newTotals3[Pair(partyC, USD)])
assertEquals(originalTotals[Pair(partyA, GBP)], newTotals3[Pair(partyA, GBP)]) assertEquals(originalTotals[Pair(partyA, GBP)], newTotals3[Pair(partyA, GBP)])
assertEquals(originalTotals[Pair(partyB, GBP)], newTotals3[Pair(partyB, 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.crypto.SecureHash
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.transactions.LedgerTransaction 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.MEGA_CORP
import net.corda.testing.MINI_CORP import net.corda.testing.MINI_CORP
import net.corda.testing.ledger 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.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.testing.* import net.corda.testing.*
import org.junit.Test import org.junit.Test
import java.security.PublicKey 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.transactions.SignedTransaction
import net.corda.core.internal.Emoji import net.corda.core.internal.Emoji
import net.corda.core.utilities.getOrThrow 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.flows.CashIssueFlow
import net.corda.node.internal.CordaRPCOpsImpl import net.corda.node.internal.CordaRPCOpsImpl
import net.corda.node.services.startFlowPermission 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.contracts.asset.Cash
import net.corda.core.contracts.Amount 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.contracts.Issued
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.transactions.TransactionBuilder 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.contracts.asset.Cash
import net.corda.core.contracts.Amount 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.contracts.Issued
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.transactions.TransactionBuilder 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.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.finance.POUNDS
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import org.junit.Before 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 If you specifically need well known identities, use the network map, which is the authoritative source of current well
known identities. known identities.
* Currency-related API in ``net.corda.core.contracts.ContractsDSL`` has moved to ```net.corda.finance.CurrencyUtils`.
Milestone 14 Milestone 14
------------ ------------

View File

@ -2,13 +2,12 @@ package net.corda.docs
import net.corda.contracts.asset.Cash import net.corda.contracts.asset.Cash
import net.corda.core.concurrent.CordaFuture 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.internal.concurrent.transpose
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.messaging.vaultTrackBy import net.corda.core.messaging.vaultTrackBy
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
import net.corda.core.node.services.Vault 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.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.flows.CashIssueFlow import net.corda.flows.CashIssueFlow

View File

@ -3,7 +3,7 @@ package net.corda.docs
import net.corda.client.rpc.notUsed import net.corda.client.rpc.notUsed
import net.corda.contracts.asset.Cash import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount 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.CordaRPCOps
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.messaging.vaultQueryBy 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.node.services.ServiceInfo
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.finance.*
import net.corda.flows.CashIssueFlow import net.corda.flows.CashIssueFlow
import net.corda.node.services.network.NetworkMapService import net.corda.node.services.network.NetworkMapService
import net.corda.node.services.transactions.ValidatingNotaryService import net.corda.node.services.transactions.ValidatingNotaryService

View File

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

View File

@ -1,6 +1,6 @@
package net.corda.contracts.universal package net.corda.contracts.universal
import net.corda.core.contracts.USD import net.corda.finance.USD
import org.junit.Ignore import org.junit.Ignore
import org.junit.Test 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.contracts.asset.Cash
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.contracts.InsufficientBalanceException 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.flows.StartableByRPC
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.services.queryBy import net.corda.core.node.services.queryBy

View File

@ -3,7 +3,7 @@ package net.corda.flows
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.Cash import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount 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.FinalityFlow
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.flows.TransactionKeyFlow import net.corda.core.flows.TransactionKeyFlow

View File

@ -2,7 +2,9 @@ package net.corda.flows
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.asset.Cash 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.flows.*
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.serialization.CordaSerializable 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.OpaqueBytes
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.unwrap 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.* import java.util.*
/** /**

View File

@ -6,8 +6,8 @@ import net.corda.core.identity.AnonymousParty;
import net.corda.core.utilities.OpaqueBytes; import net.corda.core.utilities.OpaqueBytes;
import org.junit.Test; import org.junit.Test;
import static net.corda.core.contracts.ContractsDSL.DOLLARS; import static net.corda.finance.CurrencyUtils.DOLLARS;
import static net.corda.core.contracts.ContractsDSL.issuedBy; import static net.corda.finance.CurrencyUtils.issuedBy;
import static net.corda.testing.CoreTestUtils.*; 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.transactions.TransactionBuilder
import net.corda.core.utilities.days import net.corda.core.utilities.days
import net.corda.core.utilities.seconds 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.*
import net.corda.testing.contracts.fillWithSomeTestCash import net.corda.testing.contracts.fillWithSomeTestCash
import net.corda.testing.node.MockServices 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.TransactionBuilder
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.finance.*
import net.corda.node.services.vault.NodeVaultService import net.corda.node.services.vault.NodeVaultService
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.testing.* 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.OpaqueBytes
import net.corda.core.utilities.days import net.corda.core.utilities.days
import net.corda.core.utilities.hours import net.corda.core.utilities.hours
import net.corda.finance.*
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.DummyState import net.corda.testing.contracts.DummyState
import net.corda.testing.node.MockServices 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 package net.corda.flows
import net.corda.contracts.asset.Cash import net.corda.contracts.asset.Cash
import net.corda.core.contracts.DOLLARS import net.corda.finance.DOLLARS
import net.corda.core.contracts.`issued by` import net.corda.finance.`issued by`
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow

View File

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

View File

@ -1,8 +1,8 @@
package net.corda.flows package net.corda.flows
import net.corda.contracts.asset.Cash import net.corda.contracts.asset.Cash
import net.corda.core.contracts.DOLLARS import net.corda.finance.DOLLARS
import net.corda.core.contracts.`issued by` import net.corda.finance.`issued by`
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.services.Vault import net.corda.core.node.services.Vault
import net.corda.core.node.services.trackBy 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.contracts.asset.Cash
import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.CordaFuture
import net.corda.testing.contracts.calculateRandomlySizedAmounts
import net.corda.core.contracts.Amount 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.flows.FlowException
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.services.Vault import net.corda.core.node.services.Vault
import net.corda.core.node.services.trackBy import net.corda.core.node.services.trackBy
import net.corda.core.node.services.vault.QueryCriteria import net.corda.core.node.services.vault.QueryCriteria
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS
import net.corda.flows.IssuerFlow.IssuanceRequester import net.corda.flows.IssuerFlow.IssuanceRequester
import net.corda.testing.contracts.calculateRandomlySizedAmounts
import net.corda.testing.expect import net.corda.testing.expect
import net.corda.testing.expectEvents import net.corda.testing.expectEvents
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
@ -109,7 +108,7 @@ class IssuerFlowTest(val anonymous: Boolean) {
val notary = notaryNode.services.myInfo.notaryIdentity val notary = notaryNode.services.myInfo.notaryIdentity
// try to issue an amount of a restricted currency // try to issue an amount of a restricted currency
assertFailsWith<FlowException> { 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() bankClientNode.info.legalIdentity, OpaqueBytes.of(123), notary).getOrThrow()
} }
} }

View File

@ -2,7 +2,7 @@ package net.corda.node
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import com.google.common.base.Stopwatch 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.FlowLogic
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.concurrent.transpose

View File

@ -1,7 +1,7 @@
package net.corda.node.services package net.corda.node.services
import net.corda.core.contracts.Amount 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.identity.Party
import net.corda.core.internal.bufferUntilSubscribed import net.corda.core.internal.bufferUntilSubscribed
import net.corda.core.messaging.CordaRPCOps 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.utilities.getOrThrow
import net.corda.core.node.services.queryBy import net.corda.core.node.services.queryBy
import net.corda.core.utilities.OpaqueBytes 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.CashIssueFlow
import net.corda.flows.CashPaymentFlow import net.corda.flows.CashPaymentFlow
import net.corda.node.internal.CordaRPCOpsImpl 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.getOrThrow
import net.corda.core.utilities.toNonEmptySet import net.corda.core.utilities.toNonEmptySet
import net.corda.core.utilities.unwrap 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.Buyer
import net.corda.flows.TwoPartyTradeFlow.Seller import net.corda.flows.TwoPartyTradeFlow.Seller
import net.corda.node.internal.AbstractNode 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.schemas.PersistentStateRef
import net.corda.core.serialization.deserialize import net.corda.core.serialization.deserialize
import net.corda.core.transactions.SignedTransaction 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.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.vault.VaultSchemaV1 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.contracts.asset.Cash
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.contracts.Issued 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.FlowLogic
import net.corda.core.flows.InitiatedBy import net.corda.core.flows.InitiatedBy
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow

View File

@ -5,7 +5,7 @@ import co.paralleluniverse.fibers.Suspendable
import co.paralleluniverse.strands.concurrent.Semaphore import co.paralleluniverse.strands.concurrent.Semaphore
import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.CordaFuture
import net.corda.core.contracts.ContractState 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.contracts.StateAndRef
import net.corda.core.crypto.generateKeyPair import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.random63BitValue 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.NonEmptySet
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.toNonEmptySet import net.corda.core.utilities.toNonEmptySet
import net.corda.finance.*
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash 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.*
import net.corda.core.node.services.vault.QueryCriteria.* import net.corda.core.node.services.vault.QueryCriteria.*
import net.corda.core.utilities.* import net.corda.core.utilities.*
import net.corda.finance.*
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase import net.corda.node.utilities.configureDatabase
import net.corda.schemas.CashSchemaV1 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
import net.corda.contracts.asset.DUMMY_CASH_ISSUER_KEY import net.corda.contracts.asset.DUMMY_CASH_ISSUER_KEY
import net.corda.contracts.getCashBalance 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.identity.AnonymousParty
import net.corda.core.node.services.Vault import net.corda.core.node.services.Vault
import net.corda.core.node.services.VaultQueryService 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
import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria import net.corda.core.node.services.vault.QueryCriteria.VaultQueryCriteria
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.finance.*
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.* import net.corda.testing.contracts.*

View File

@ -1,9 +1,8 @@
package net.corda.bank package net.corda.bank
import net.corda.contracts.asset.Cash 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.startFlow
import net.corda.core.messaging.vaultTrackBy
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
import net.corda.core.node.services.Vault import net.corda.core.node.services.Vault
import net.corda.core.node.services.vault.QueryCriteria 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.bank.api.BankOfCordaWebApi.IssueRequestParams
import net.corda.client.rpc.CordaRPCClient import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.contracts.currency
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.flows.IssuerFlow.IssuanceRequester import net.corda.flows.IssuerFlow.IssuanceRequester
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.http.HttpApi import net.corda.testing.http.HttpApi
import java.util.*
/** /**
* Interface for communicating with Bank of Corda node * Interface for communicating with Bank of Corda node
@ -46,7 +45,7 @@ class BankOfCordaClientApi(val hostAndPort: NetworkHostAndPort) {
val notaryNode = rpc.nodeIdentityFromParty(notaryLegalIdentity) val notaryNode = rpc.nodeIdentityFromParty(notaryLegalIdentity)
?: throw IllegalStateException("Unable to locate notary node in network map cache") ?: 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()) val issuerToPartyRef = OpaqueBytes.of(params.issueToPartyRefAsString.toByte())
return rpc.startFlow(::IssuanceRequester, amount, issueToParty, issuerToPartyRef, issuerBankParty, notaryNode.notaryIdentity, params.anonymous) return rpc.startFlow(::IssuanceRequester, amount, issueToParty, issuerToPartyRef, issuerBankParty, notaryNode.notaryIdentity, params.anonymous)

View File

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

View File

@ -1,10 +1,13 @@
package net.corda.irs.contract package net.corda.irs.contract
import net.corda.contracts.* 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.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.finance.DOLLARS
import net.corda.finance.EUR
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import org.junit.Test import org.junit.Test
@ -79,8 +82,6 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
fixedLegPaymentSchedule = mutableMapOf() fixedLegPaymentSchedule = mutableMapOf()
) )
val EUR = currency("EUR")
val common = InterestRateSwap.Common( val common = InterestRateSwap.Common(
baseCurrency = EUR, baseCurrency = EUR,
eligibleCurrency = EUR, eligibleCurrency = EUR,
@ -169,8 +170,6 @@ fun createDummyIRS(irsSelect: Int): InterestRateSwap.State {
fixedLegPaymentSchedule = mutableMapOf() fixedLegPaymentSchedule = mutableMapOf()
) )
val EUR = currency("EUR")
val common = InterestRateSwap.Common( val common = InterestRateSwap.Common(
baseCurrency = EUR, baseCurrency = EUR,
eligibleCurrency = 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.LedgerTransaction
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.finance.GBP
@StartableByRPC @StartableByRPC
class DummyIssueAndMove(private val notary: Party, private val counterpartyNode: Party, private val discriminator: Int) : FlowLogic<SignedTransaction>() { 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 package net.corda.traderdemo
import net.corda.client.rpc.CordaRPCClient 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.internal.concurrent.transpose
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.getOrThrow 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.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.startFlowPermission
import net.corda.node.services.transactions.SimpleNotaryService import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.testing.BOC 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.driver.poll
import net.corda.testing.node.NodeBasedTest import net.corda.testing.node.NodeBasedTest
import net.corda.traderdemo.flow.BuyerFlow import net.corda.traderdemo.flow.BuyerFlow
@ -30,7 +29,7 @@ class TraderDemoTest : NodeBasedTest() {
val demoUser = User("demo", "demo", setOf(startFlowPermission<SellerFlow>())) val demoUser = User("demo", "demo", setOf(startFlowPermission<SellerFlow>()))
val bankUser = User("user1", "test", permissions = setOf(startFlowPermission<CashIssueFlow>(), val bankUser = User("user1", "test", permissions = setOf(startFlowPermission<CashIssueFlow>(),
startFlowPermission<CommercialPaperIssueFlow>())) startFlowPermission<CommercialPaperIssueFlow>()))
val (nodeA, nodeB, bankNode, notaryNode) = listOf( val (nodeA, nodeB, bankNode) = listOf(
startNode(DUMMY_BANK_A.name, rpcUsers = listOf(demoUser)), startNode(DUMMY_BANK_A.name, rpcUsers = listOf(demoUser)),
startNode(DUMMY_BANK_B.name, rpcUsers = listOf(demoUser)), startNode(DUMMY_BANK_B.name, rpcUsers = listOf(demoUser)),
startNode(BOC.name, rpcUsers = listOf(bankUser)), startNode(BOC.name, rpcUsers = listOf(bankUser)),
@ -57,7 +56,7 @@ class TraderDemoTest : NodeBasedTest() {
val expectedPaper = listOf(clientA.commercialPaperCount + 1, clientB.commercialPaperCount) val expectedPaper = listOf(clientA.commercialPaperCount + 1, clientB.commercialPaperCount)
// TODO: Enable anonymisation // 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) clientB.runSeller(buyerName = nodeA.info.legalIdentity.name, amount = 5.DOLLARS)
assertThat(clientA.cashCount).isGreaterThan(originalACash) assertThat(clientA.cashCount).isGreaterThan(originalACash)

View File

@ -2,12 +2,11 @@ package net.corda.traderdemo
import joptsimple.OptionParser import joptsimple.OptionParser
import net.corda.client.rpc.CordaRPCClient import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.DOLLARS
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.finance.DOLLARS
import net.corda.testing.DUMMY_BANK_A import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.DUMMY_NOTARY
import org.slf4j.Logger import org.slf4j.Logger
import kotlin.system.exitProcess import kotlin.system.exitProcess
@ -28,8 +27,6 @@ private class TraderDemo {
val logger: Logger = loggerFor<TraderDemo>() val logger: Logger = loggerFor<TraderDemo>()
val buyerName = DUMMY_BANK_A.name val buyerName = DUMMY_BANK_A.name
val sellerName = DUMMY_BANK_B.name val sellerName = DUMMY_BANK_B.name
val notaryName = DUMMY_NOTARY.name
val buyerRpcPort = 10006
val sellerRpcPort = 10009 val sellerRpcPort = 10009
val bankRpcPort = 10012 val bankRpcPort = 10012
} }
@ -52,7 +49,7 @@ private class TraderDemo {
if (role == Role.BANK) { if (role == Role.BANK) {
val bankHost = NetworkHostAndPort("localhost", bankRpcPort) val bankHost = NetworkHostAndPort("localhost", bankRpcPort)
CordaRPCClient(bankHost).use("demo", "demo") { CordaRPCClient(bankHost).use("demo", "demo") {
TraderDemoClientApi(it.proxy).runIssuer(1100.DOLLARS, buyerName, sellerName, notaryName) TraderDemoClientApi(it.proxy).runIssuer(1100.DOLLARS, buyerName, sellerName)
} }
} else { } else {
val sellerHost = NetworkHostAndPort("localhost", sellerRpcPort) 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.asset.Cash
import net.corda.contracts.getCashBalance import net.corda.contracts.getCashBalance
import net.corda.core.contracts.Amount 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.Emoji
import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.concurrent.transpose
import net.corda.core.messaging.CordaRPCOps 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.node.services.vault.builder
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow 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.flows.CashIssueFlow
import net.corda.node.services.vault.VaultSchemaV1 import net.corda.node.services.vault.VaultSchemaV1
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
@ -29,10 +28,6 @@ import java.util.*
* Interface for communicating with nodes running the trader demo. * Interface for communicating with nodes running the trader demo.
*/ */
class TraderDemoClientApi(val rpc: CordaRPCOps) { class TraderDemoClientApi(val rpc: CordaRPCOps) {
private companion object {
val logger = loggerFor<TraderDemoClientApi>()
}
val cashCount: Long get() { val cashCount: Long get() {
val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() } val count = builder { VaultSchemaV1.VaultStates::recordedTime.count() }
val countCriteria = QueryCriteria.VaultCustomQueryCriteria(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 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 ref = OpaqueBytes.of(1)
val buyer = rpc.partyFromX500Name(buyerName) ?: throw IllegalStateException("Don't know $buyerName") val buyer = rpc.partyFromX500Name(buyerName) ?: throw IllegalStateException("Don't know $buyerName")
val seller = rpc.partyFromX500Name(sellerName) ?: throw IllegalStateException("Don't know $sellerName") 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. // 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") println("Commercial paper issued to seller")
} }

View File

@ -2,16 +2,14 @@ package net.corda.traderdemo.flow
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.contracts.CommercialPaper import net.corda.contracts.CommercialPaper
import net.corda.contracts.asset.DUMMY_CASH_ISSUER
import net.corda.core.contracts.Amount 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.crypto.SecureHash
import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatingFlow import net.corda.core.flows.InitiatingFlow
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes 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.client.rpc.CordaRPCConnection
import net.corda.contracts.asset.Cash import net.corda.contracts.asset.Cash
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.contracts.GBP import net.corda.finance.GBP
import net.corda.core.contracts.USD import net.corda.finance.USD
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.messaging.CordaRPCOps 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.model.observableValue
import net.corda.client.jfx.utils.ChosenList import net.corda.client.jfx.utils.ChosenList
import net.corda.client.jfx.utils.map import net.corda.client.jfx.utils.map
import net.corda.core.contracts.currency
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import tornadofx.* import tornadofx.*
import java.util.*
val ISSUER_SERVICE_TYPE = Regex("corda.issuer.(USD|GBP|CHF|EUR)") val ISSUER_SERVICE_TYPE = Regex("corda.issuer.(USD|GBP|CHF|EUR)")
@ -34,7 +34,7 @@ class IssuerModel {
private fun NodeInfo.issuerCurrency() = if (isIssuerNode()) { private fun NodeInfo.issuerCurrency() = if (isIssuerNode()) {
val issuer = advertisedServices.first { it.info.type.id.matches(ISSUER_SERVICE_TYPE) } 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 } else
null 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.model.observableValue
import net.corda.client.jfx.utils.AmountBindings import net.corda.client.jfx.utils.AmountBindings
import net.corda.core.contracts.* 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 org.fxmisc.easybind.EasyBind
import tornadofx.* import tornadofx.*
import java.util.* import java.util.*

View File

@ -4,7 +4,6 @@ import javafx.beans.InvalidationListener
import javafx.beans.Observable import javafx.beans.Observable
import javafx.beans.property.ObjectProperty import javafx.beans.property.ObjectProperty
import javafx.beans.property.SimpleObjectProperty import javafx.beans.property.SimpleObjectProperty
import net.corda.core.contracts.currency
import net.corda.core.internal.createDirectories import net.corda.core.internal.createDirectories
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.internal.exists 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 String::class.java -> string(metadata.name, "") as T
Int::class.java -> string(metadata.name, "0").toInt() as T Int::class.java -> string(metadata.name, "0").toInt() as T
Boolean::class.java -> boolean(metadata.name) 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 Path::class.java -> Paths.get(string(metadata.name, "")).toAbsolutePath() as T
else -> throw IllegalArgumentException("Unsupported type ${metadata.returnType}") else -> throw IllegalArgumentException("Unsupported type ${metadata.returnType}")
} }

View File

@ -1,23 +1,27 @@
package net.corda.explorer.model package net.corda.explorer.model
import net.corda.core.contracts.USD import net.corda.finance.USD
import net.corda.core.contracts.currency
import org.junit.Test import org.junit.Test
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class IssuerModelTest { class IssuerModelTest {
@Test @Test
fun `test issuer regex`() { fun `test issuer regex`() {
val regex = Regex("corda.issuer.(USD|GBP|CHF)") val regex = Regex("corda.issuer.(USD|GBP|CHF)")
kotlin.test.assertTrue("corda.issuer.USD".matches(regex)) assertTrue("corda.issuer.USD".matches(regex))
kotlin.test.assertTrue("corda.issuer.GBP".matches(regex)) assertTrue("corda.issuer.GBP".matches(regex))
kotlin.test.assertFalse("corda.issuer.USD.GBP".matches(regex)) assertFalse("corda.issuer.USD.GBP".matches(regex))
kotlin.test.assertFalse("corda.issuer.EUR".matches(regex)) assertFalse("corda.issuer.EUR".matches(regex))
kotlin.test.assertFalse("corda.issuer".matches(regex)) assertFalse("corda.issuer".matches(regex))
kotlin.test.assertEquals(USD, currency("corda.issuer.USD".substringAfterLast("."))) assertEquals(USD, Currency.getInstance("corda.issuer.USD".substringAfterLast(".")))
assertFailsWith(IllegalArgumentException::class, { currency("corda.issuer.DOLLAR".substringBeforeLast(".")) }) 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.contracts.asset.Cash
import net.corda.core.contracts.Issued import net.corda.core.contracts.Issued
import net.corda.core.contracts.PartyAndReference 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.identity.AbstractParty
import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.messaging.vaultQueryBy 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.pickOne
import net.corda.client.mock.replicatePoisson import net.corda.client.mock.replicatePoisson
import net.corda.contracts.asset.Cash 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.flows.FlowException
import net.corda.core.identity.AbstractParty import net.corda.core.identity.AbstractParty
import net.corda.core.utilities.getOrThrow 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.client.mock.Generator
import net.corda.core.contracts.Amount 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.flows.FlowException
import net.corda.core.internal.concurrent.thenMatch import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes

View File

@ -1,7 +1,7 @@
package net.corda.verifier package net.corda.verifier
import net.corda.client.mock.generateOrFail 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.messaging.startFlow
import net.corda.core.node.services.ServiceInfo import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes