Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CreateObligation fails with constructor #21

Open
TAC911 opened this issue May 27, 2019 · 9 comments
Open

CreateObligation fails with constructor #21

TAC911 opened this issue May 27, 2019 · 9 comments

Comments

@TAC911
Copy link

TAC911 commented May 27, 2019

Calling the CreateObligation flow as described in the example leads to an error.

Command:
start CreateObligation amount: { quantity: 1000, token: { currencyCode: USD, type: fiat } }, role: OBLIGOR, counterparty: PartyB, dueBy: 1543922400, anonymous: false

Error:

No matching constructor found:
- [net.corda.core.contracts.Amount<T>, com.r3.corda.finance.obligation.client.flows.CreateObligation$InitiatorRole, net.corda.core.identity.Party, java.time.Instant, boolean]: Could not parse as a command: Cannot construct instance of `com.r3.corda.sdk.token.contracts.types.TokenType` (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
 at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: net.corda.core.contracts.Amount["token"])
- [net.corda.core.contracts.Amount, com.r3.corda.finance.obligation.client.flows.CreateObligation$InitiatorRole, net.corda.core.identity.Party, java.time.Instant, boolean, int, kotlin.jvm.internal.DefaultConstructorMarker]: <constructor missing parameter reflection data>

Cheers,
TAC

@roger-that-dev
Copy link

Thanks for the heads up. It's because I changed the constructor signature (added a type parameter) and the node shell can't deserialise a string to the type. I'll add a helper flow so this will work. Cheers

@roger-that-dev
Copy link

Actually I've had a look into this and there's no way to fix it in the short term, it requires some Corda changes or changes to the tokens SDK to provide jackson annotations for sub-classes. In the meantime, I'm going to include a node driver integration test which demonstrates the whole end to end workflow. Cheers

@iljadfine
Copy link

iljadfine commented Jun 7, 2019

I got a similar error for NovateObligation.
Command:
start NovateObligation linearId: b4436194-5977-4c0b-9581-dc93ee625627, novationCommand: { oldToken: { currencyCode: EUR, type: fiat }, newToken: { currencyCode: XRP, type: digital }, oracle: Oracle, type: token }
Error:

No matching constructor found:

  • [net.corda.core.contracts.UniqueIdentifier, com.r3.corda.finance.obligation.commands.ObligationCommands$Novate]: Could not parse as a command: Cannot construct instance of com.r3.corda.sdk.token.contracts.types.TokenType (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
    at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.r3.corda.finance.obligation.commands.ObligationCommands$Novate$UpdateFaceAmountToken["oldToken"])

Is it the same cause?

@roger-that-dev
Copy link

roger-that-dev commented Jun 7, 2019

Yes its the same problem. The shell cannot deserialise the types. There is one way around it which is to create a wrapper flow which just takes strings as input and then constructs the objects you need and then invokes the create obligation flow. It's not difficult to do but will get messy, e.g. you'll need to deal with whether the currency code is a fiat or digital currency, for example.

@koshikraj
Copy link

@roger3cev, I was just wondering if there is a node driver integration test for an end to end flow for ripple settlement since we are not able to test it using the shell?

@roger-that-dev
Copy link

There's not a node driver test at the moment - it's on our TODO To add one though. Cheers

@adelrustum
Copy link

adelrustum commented Aug 2, 2019

Hi guys,

UPDATE:
Here's the repo with all the below fixes:
https://github.com/adelrustum/corda-settler-fixes

I was able to use Roger's workaround (i.e. instead of passing an Amount, I passed the amount and currency code); below is how I achieved it:

  1. Add cordaCompile "$tokens_release_group:tokens-money:$tokens_release_version" into the gradle file of cordapp module so I can use FiatCurrency class.
  2. Optional: I updated the tokens-sdk version to ext.tokens_release_version = '1.0-RC03', because I noticed when I opened FiatCurrency.kt file and compared it to the latest version of tokens-sdk that they're different. This got me stuck for 2-3 hours lol not an expert on gradle/maven/intellij, but I'm getting there.
  3. Modify CreateObligation.kt and split Amount into longAmount and currencyCode; this will trigger a couple of errors because some functions expect Amount<T> instead of Amount<FiatCurrency> so I'll leave locating those easy fixes to you.
    Below is the part of the code that I changed:
class Initiator<T : TokenType>(
            private val longAmount: Long,
            private val currencyCode: String,
            private val role: InitiatorRole,
            private val counterparty: Party,
            private val dueBy: Instant? = null,
            private val anonymous: Boolean = true
    ) : FlowLogic<WireTransaction>() {
        private val token = FiatCurrency(Currency.getInstance(currencyCode))
        private val amount = Amount(longAmount, token)
  1. Use this call in your terminal to create an obligation:
start CreateObligation longAmount: 1000, currencyCode: USD, role: OBLIGOR, counterparty: PartyB, dueBy: 1650000000, anonymous: false
  1. Below is the updated NovateObligation.kt code: Again, it will trigger some errors in the class code (replace TokenType with FiatCurrencty or DigitalCurrency where applicable).
class Initiator(
            val linearId: UniqueIdentifier,
            private val fiatIdentifier: String,
            private val digitalIdentifier: String,
            private val oracle: Party
    ) : FlowLogic<WireTransaction>() {
        private val fiatToken = FiatCurrency(Currency.getInstance(fiatIdentifier))
        private val digitalToken = DigitalCurrency(digitalIdentifier)
        private val novationCommand = ObligationCommands.Novate.
                UpdateFaceAmountToken(fiatToken, digitalToken, oracle)
  1. Use this call:
start NovateObligation linearId: REPLACE_W_OBLIGATION_ID, fiatIdentifier: USD, digitalIdentifier: XRP, oracle: Oracle
  1. To fix UpdateSettlementMethod flow I had to copy the entire ripple library from modules\ripple to cordapp folder, I tried to use it first as a dependency in build.gradle but that created a circular reference error on build because ripple library relies on cordapp.
  2. Update build.gradle under cordapp with compile 'com.ripple:ripple-core:0.0.1-SNAPSHOT'
  3. Update UpdateSettlementMethod:
class Initiator(
            val linearId: UniqueIdentifier,
            val accountToPay: String,
            val settlementOracle: Party
    ) : FlowLogic<WireTransaction>() {
        private val settlementMethod = XrpSettlement(accountToPay, settlementOracle)
  1. Run this from PartyB terminal (not PartyA):
    start UpdateSettlementMethod linearId: REPLACE_W_OBLIGATION_UID, accountToPay: REPLACE_W_XRP_ADDRESS, settlementOracle: Oracle
  2. Update OffLedgerSettleObligation flow:
class Initiator<T : TokenType>(
            private val longAmount: Long,
            private val digitalIdentifier: String,
            private val linearId: UniqueIdentifier
    ) : FlowLogic<WireTransaction>() {
        private val token = DigitalCurrency(digitalIdentifier)
        private val amount = Amount(longAmount, token)
  1. Run this from PartyA terminal:
    start OffLedgerSettleObligation longAmount: 20000000, digitalIdentifier: XRP, linearId: REPLACE_W_OBLIGATION_UID

@koshikraj
Copy link

Hi guys,

UPDATE:
Here's the repo with all the below fixes:
https://github.com/adelRestom/corda-settler-fixes

I was able to use Roger's workaround (i.e. instead of passing an Amount, I passed the amount and currency code); below is how I achieved it:

  1. Add cordaCompile "$tokens_release_group:tokens-money:$tokens_release_version" into the gradle file of cordapp module so I can use FiatCurrency class.
  2. Optional: I updated the tokens-sdk version to ext.tokens_release_version = '1.0-RC03', because I noticed when I opened FiatCurrency.kt file and compared it to the latest version of tokens-sdk that they're different. This got me stuck for 2-3 hours lol not an expert on gradle/maven/intellij, but I'm getting there.
  3. Modify CreateObligation.kt and split Amount into longAmount and currencyCode; this will trigger a couple of errors because some functions expect Amount<T> instead of Amount<FiatCurrency> so I'll leave locating those easy fixes to you.
    Below is the part of the code that I changed:
class Initiator<T : TokenType>(
            private val longAmount: Long,
            private val currencyCode: String,
            private val role: InitiatorRole,
            private val counterparty: Party,
            private val dueBy: Instant? = null,
            private val anonymous: Boolean = true
    ) : FlowLogic<WireTransaction>() {
        private val token = FiatCurrency(Currency.getInstance(currencyCode))
        private val amount = Amount(longAmount, token)
  1. Use this call in your terminal to create an obligation:
start CreateObligation longAmount: 1000, currencyCode: USD, role: OBLIGOR, counterparty: PartyB, dueBy: 1650000000, anonymous: false
  1. Below is the updated NovateObligation.kt code: Again, it will trigger some errors in the class code (replace TokenType with FiatCurrencty or DigitalCurrency where applicable).
class Initiator(
            val linearId: UniqueIdentifier,
            private val fiatIdentifier: String,
            private val digitalIdentifier: String,
            private val oracle: Party
    ) : FlowLogic<WireTransaction>() {
        private val fiatToken = FiatCurrency(Currency.getInstance(fiatIdentifier))
        private val digitalToken = DigitalCurrency(digitalIdentifier)
        private val novationCommand = ObligationCommands.Novate.
                UpdateFaceAmountToken(fiatToken, digitalToken, oracle)
  1. Use this call:
start NovateObligation linearId: REPLACE_W_OBLIGATION_ID, fiatIdentifier: USD, digitalIdentifier: XRP, oracle: Oracle
  1. To fix UpdateSettlementMethod flow I had to copy the entire ripple library from modules\ripple to cordapp folder, I tried to use it first as a dependency in build.gradle but that created a circular reference error on build because ripple library relies on cordapp.
  2. Update build.gradle under cordapp with compile 'com.ripple:ripple-core:0.0.1-SNAPSHOT'
  3. Update UpdateSettlementMethod:
class Initiator(
            val linearId: UniqueIdentifier,
            val accountToPay: String,
            val settlementOracle: Party
    ) : FlowLogic<WireTransaction>() {
        private val settlementMethod = XrpSettlement(accountToPay, settlementOracle)
  1. Run this from PartyB terminal (not PartyA):
    start NovateObligation linearId: REPLACE_W_OBLIGATION_UID, fiatIdentifier: USD, digitalIdentifier: XRP, oracle: Oracle
  2. Update OffLedgerSettleObligation flow:
class Initiator<T : TokenType>(
            private val longAmount: Long,
            private val digitalIdentifier: String,
            private val linearId: UniqueIdentifier
    ) : FlowLogic<WireTransaction>() {
        private val token = DigitalCurrency(digitalIdentifier)
        private val amount = Amount(longAmount, token)
  1. Run this from PartyA terminal:
    start OffLedgerSettleObligation longAmount: 20000000, digitalIdentifier: XRP, linearId: REPLACE_W_OBLIGATION_UID

Thanks for the fix. I was able to test the end to end flow on the Corda shell.

@adelrustum
Copy link

@koshikraj Thanx for your merge request, I also updated the comment here to remove the repeated instruction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants