-
Notifications
You must be signed in to change notification settings - Fork 36
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
Added manual settlement rail #20
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR looks great! Thanks for the contribution. Just had a few comments. Let me know if you have any questions on the comments. Cheers!
manual/src/main/kotlin/com.r3.corda.finance.manual/types/ManualSettlement.kt
Outdated
Show resolved
Hide resolved
|
||
import net.corda.core.contracts.Contract | ||
import net.corda.core.transactions.LedgerTransaction | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yah, I'm not quite sure how the jar attachment and class loader works here. I was getting errors about not finding the attachment for certain classes. I can try again without this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried again without the DummyContract and got:
[ERROR] 2019-05-24T17:45:40,068Z [Node thread-1] transactions.TransactionBuilder.addMissingAttachment - The transaction currently built is missing an attachment for class: com/r3/corda/finance/obligation/client/flows/MakeOffLedgerPayment.
Attempted to find a suitable attachment but could not find any in the storage.
Please contact the developer of the CorDapp for further instructions. {actor_id=admin, actor_owning_identity=CN=party2, O=Party2, L=Calgary, C=CA, actor_store_id=NODE_CONFIG, fiber-id=10000011, flow-id=659ad3e0-782d-499d-bf94-bcf82c121f1d, invocation_id=c7976465-392d-4ef9-8186-c114975b11a1, invocation_timestamp=2019-05-24T17:45:37.310Z, origin=admin, session_id=e2027977-e1bc-4464-af6a-05547df67cd8, session_timestamp=2019-05-24T17:44:14.174Z, thread-id=474}
[INFO ] 2019-05-24T17:45:40,068Z [Node thread-1] corda.flow.run - Flow raised an error: com/r3/corda/finance/obligation/client/flows/MakeOffLedgerPayment. Sending it to flow hospital to be triaged. {actor_id=admin, actor_owning_identity=CN=party2, O=Party2, L=Calgary, C=CA, actor_store_id=NODE_CONFIG, fiber-id=10000011, flow-id=659ad3e0-782d-499d-bf94-bcf82c121f1d, invocation_id=c7976465-392d-4ef9-8186-c114975b11a1, invocation_timestamp=2019-05-24T17:45:37.310Z, origin=admin, session_id=e2027977-e1bc-4464-af6a-05547df67cd8, session_timestamp=2019-05-24T17:44:14.174Z, thread-id=474}
and
java.lang.NoClassDefFoundError: com/r3/corda/finance/obligation/client/flows/MakeOffLedgerPayment
at java.lang.ClassLoader.defineClass1(Native Method) ~[?:1.8.0_212]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:1.8.0_212]
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[?:1.8.0_212]
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468) ~[?:1.8.0_212]
at java.net.URLClassLoader.access$100(URLClassLoader.java:74) ~[?:1.8.0_212]
at java.net.URLClassLoader$1.run(URLClassLoader.java:369) ~[?:1.8.0_212]
at java.net.URLClassLoader$1.run(URLClassLoader.java:363) ~[?:1.8.0_212]
at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0_212]
at java.net.URLClassLoader.findClass(URLClassLoader.java:362) ~[?:1.8.0_212]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_212]
at java.lang.ClassLoader.loadClass(ClassLoader.java:411) ~[?:1.8.0_212]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_212]
at java.lang.Class.forName0(Native Method) ~[?:1.8.0_212]
at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_212]
at net.corda.serialization.internal.model.TypeIdentifier$Parameterised.getLocalType(TypeIdentifier.kt:209) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.model.TypeIdentifier$Parameterised.getLocalType(TypeIdentifier.kt:218) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.model.ClassCarpentingTypeLoader$load$noCarpentryRequired$1$1.apply(TypeLoader.kt:38) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.model.ClassCarpentingTypeLoader$load$noCarpentryRequired$1$1.apply(TypeLoader.kt:25) ~[corda-serialization-4.1-RC03.jar:?]
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[?:1.8.0_212]
at net.corda.serialization.internal.model.ClassCarpentingTypeLoader$load$noCarpentryRequired$1.invoke(TypeLoader.kt:38) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.model.ClassCarpentingTypeLoader$load$noCarpentryRequired$1.invoke(TypeLoader.kt:25) ~[corda-serialization-4.1-RC03.jar:?]
at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:149) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at kotlin.sequences.FilteringSequence$iterator$1.calcNext(Sequences.kt:109) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at kotlin.sequences.FilteringSequence$iterator$1.hasNext(Sequences.kt:133) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at kotlin.collections.MapsKt__MapsKt.putAll(Maps.kt:339) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at kotlin.collections.MapsKt__MapsKt.toMap(Maps.kt:504) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at kotlin.collections.MapsKt__MapsKt.toMap(Maps.kt:498) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at net.corda.serialization.internal.model.ClassCarpentingTypeLoader.load(TypeLoader.kt:45) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.reflect(RemoteSerializerFactory.kt:130) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.access$reflect(RemoteSerializerFactory.kt:48) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1.invoke(RemoteSerializerFactory.kt:72) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory$get$1.invoke(RemoteSerializerFactory.kt:48) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DefaultDescriptorBasedSerializerRegistry.getOrBuild(DescriptorBasedSerializerRegistry.kt:28) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DefaultRemoteSerializerFactory.get(RemoteSerializerFactory.kt:67) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposedSerializerFactory.get(SerializerFactory.kt) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.readObject$serialization(DeserializationInput.kt:172) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.readObjectOrNull$serialization(DeserializationInput.kt:147) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DescribedTypeReadStrategy.readProperty(ComposableTypePropertySerializer.kt:202) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableTypePropertySerializer.readProperty(ComposableTypePropertySerializer.kt) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableObjectReader$readObject$$inlined$ifThrowsAppend$lambda$1.invoke(ObjectSerializer.kt:140) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableObjectReader$readObject$$inlined$ifThrowsAppend$lambda$1.invoke(ObjectSerializer.kt:122) ~[corda-serialization-4.1-RC03.jar:?]
at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:149) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at net.corda.serialization.internal.amqp.ComposableObjectReader.readObject(ObjectSerializer.kt:219) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableObjectSerializer.readObject(ObjectSerializer.kt:91) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.readObject$serialization(DeserializationInput.kt:182) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.readObjectOrNull$serialization(DeserializationInput.kt:147) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DescribedTypeReadStrategy.readProperty(ComposableTypePropertySerializer.kt:202) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableTypePropertySerializer.readProperty(ComposableTypePropertySerializer.kt) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableObjectReader$readObject$$inlined$ifThrowsAppend$lambda$1.invoke(ObjectSerializer.kt:140) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableObjectReader$readObject$$inlined$ifThrowsAppend$lambda$1.invoke(ObjectSerializer.kt:122) ~[corda-serialization-4.1-RC03.jar:?]
at kotlin.sequences.TransformingSequence$iterator$1.next(Sequences.kt:149) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at net.corda.serialization.internal.amqp.ComposableObjectReader.readObject(ObjectSerializer.kt:219) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.ComposableObjectSerializer.readObject(ObjectSerializer.kt:91) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.readObject$serialization(DeserializationInput.kt:182) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.readObjectOrNull$serialization(DeserializationInput.kt:147) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput$deserialize$1.invoke(DeserializationInput.kt:124) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.des(DeserializationInput.kt:99) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.DeserializationInput.deserialize(DeserializationInput.kt:119) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.amqp.AbstractAMQPSerializationScheme.deserialize(AMQPSerializationScheme.kt:225) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1$1.invoke(SerializationScheme.kt:105) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.core.serialization.SerializationFactory.withCurrentContext(SerializationAPI.kt:71) ~[corda-core-4.1-RC03.jar:?]
at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1.invoke(SerializationScheme.kt:105) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.serialization.internal.SerializationFactoryImpl$deserialize$1.invoke(SerializationScheme.kt:73) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.core.serialization.SerializationFactory.asCurrent(SerializationAPI.kt:85) ~[corda-core-4.1-RC03.jar:?]
at net.corda.serialization.internal.SerializationFactoryImpl.deserialize(SerializationScheme.kt:105) ~[corda-serialization-4.1-RC03.jar:?]
at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt:78) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.internal.TransactionUtilsKt$deserialiseComponentGroup$1.invoke(TransactionUtils.kt) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.internal.LazyMappedList.get(InternalUtils.kt:552) ~[corda-core-4.1-RC03.jar:?]
at java.util.AbstractList$Itr.next(AbstractList.java:358) ~[?:1.8.0_212]
at java.util.AbstractCollection.toArray(AbstractCollection.java:141) ~[?:1.8.0_212]
at java.util.ArrayList.addAll(ArrayList.java:581) ~[?:1.8.0_212]
at kotlin.collections.CollectionsKt___CollectionsKt.plus(_Collections.kt:1970) ~[kotlin-stdlib-1.2.71.jar:1.2.71-release-64 (1.2.71)]
at net.corda.core.internal.Verifier.<init>(TransactionVerifierServiceInternal.kt:33) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.LedgerTransaction$internalPrepareVerify$1.invoke(LedgerTransaction.kt:148) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.LedgerTransaction$internalPrepareVerify$1.invoke(LedgerTransaction.kt:45) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder$withAttachmentsClassloaderContext$1.invoke(AttachmentsClassLoader.kt:339) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.serialization.SerializationFactory.withCurrentContext(SerializationAPI.kt:71) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext(AttachmentsClassLoader.kt:338) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.serialization.internal.AttachmentsClassLoaderBuilder.withAttachmentsClassloaderContext$default(AttachmentsClassLoader.kt:314) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.LedgerTransaction.internalPrepareVerify$core(LedgerTransaction.kt:144) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.LedgerTransaction.verify(LedgerTransaction.kt:134) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.addMissingDependency(TransactionBuilder.kt:186) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.toWireTransactionWithContext$core(TransactionBuilder.kt:166) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.toWireTransactionWithContext$core(TransactionBuilder.kt:169) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.toWireTransactionWithContext$core(TransactionBuilder.kt:169) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.toWireTransactionWithContext$core(TransactionBuilder.kt:169) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.toWireTransactionWithContext$core$default(TransactionBuilder.kt:134) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.toWireTransaction(TransactionBuilder.kt:131) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.transactions.TransactionBuilder.toSignedTransaction(TransactionBuilder.kt:711) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.node.ServiceHub$DefaultImpls.signInitialTransaction(ServiceHub.kt:232) ~[corda-core-4.1-RC03.jar:?]
at net.corda.core.node.ServiceHub$DefaultImpls.signInitialTransaction(ServiceHub.kt:246) ~[corda-core-4.1-RC03.jar:?]
at net.corda.node.services.api.ServiceHubInternal$DefaultImpls.signInitialTransaction(ServiceHubInternal.kt) ~[corda-node-4.1-RC03.jar:?]
at net.corda.node.internal.AbstractNode$ServiceHubInternalImpl.signInitialTransaction(AbstractNode.kt:962) ~[corda-node-4.1-RC03.jar:?]
at net.corda.core.node.ServiceHub$DefaultImpls.signInitialTransaction(ServiceHub.kt:268) ~[corda-core-4.1-RC03.jar:?]
at net.corda.node.services.api.ServiceHubInternal$DefaultImpls.signInitialTransaction(ServiceHubInternal.kt) ~[corda-node-4.1-RC03.jar:?]
at net.corda.node.internal.AbstractNode$ServiceHubInternalImpl.signInitialTransaction(AbstractNode.kt:962) ~[corda-node-4.1-RC03.jar:?]
at com.r3.corda.finance.obligation.client.flows.UpdateSettlementMethod$Initiator.call(UpdateSettlementMethod.kt:73) ~[?:?]
at com.r3.corda.finance.obligation.client.flows.UpdateSettlementMethod$Initiator.call(UpdateSettlementMethod.kt:22) ~[?:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:269) ~[corda-node-4.1-RC03.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:45) ~[corda-node-4.1-RC03.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) ~[quasar-core-0.7.10-jdk8.jar:0.7.10]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_212]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) ~[?:1.8.0_212]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) ~[?:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_212]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_212]
at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:63) ~[corda-node-4.1-RC03.jar:?]
Caused by: java.lang.ClassNotFoundException: com.r3.corda.finance.obligation.client.flows.MakeOffLedgerPayment
at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[?:1.8.0_212]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0_212]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0_212]
at net.corda.core.serialization.internal.AttachmentsClassLoader.loadClass(AttachmentsClassLoader.kt:288) ~[corda-core-4.1-RC03.jar:?]
... 111 more
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, my bad. I forgot about this... To enable CorDapp dependencies to work, the transaction class loader searches for jars containing the needed classes but it will only search JARs with contract implementations in. Presumably we'll get to fixing this in the next point release. Cheers
cordapp/src/main/kotlin/com/r3/corda/finance/obligation/client/flows/UpdatePaymentStatus.kt
Outdated
Show resolved
Hide resolved
cordapp/src/main/kotlin/com/r3/corda/finance/obligation/client/flows/UpdatePaymentStatus.kt
Outdated
Show resolved
Hide resolved
manual/src/main/kotlin/com.r3.corda.finance.manual/contract/DummyContract.kt
Show resolved
Hide resolved
cordapp/src/main/kotlin/com/r3/corda/finance/obligation/client/flows/SendToSettlementOracle.kt
Outdated
Show resolved
Hide resolved
Not sure how I request another review. I'll just add a comment here. |
Hi @countfloyd , may I ask what are you trying to do with this manual module? Is this a settlement rail you have created for yourself? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for addressing my comments - I added a couple of more for information (no need to action any of them). The only thing I'd ask is that is it possible for you to add a test for the manual settlement mechanism and some unit tests? Other than that, I think this is good to merge. Many thanks for the contribution!
Update: Forgot to mention that the other thing which needs adding is some contract code for cancelling an obligation. Cheers!
/** Represents a manual payment. */ | ||
data class ManualPayment( | ||
override val paymentReference: PaymentReference, | ||
override val amount: Amount<FiatCurrency>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to do anything, more a note for me, is that this could be generalised to enable manual delivery of any TokenType
, e.g. shares.
check(ourIdentity == obligee) { "This flow can only be started by the obligee. " } | ||
val obligor = serviceHub.identityService.requireWellKnownPartyFromAnonymous(os.obligor) | ||
val payment = obligationState.payments.find { it.paymentReference == paymentReference } | ||
check(payment != null) { "Could not find payment with reference '$paymentReference'" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use if
here to get the smart cast, so no need to subsequently use unsafe dereferencing. No need to change anything though!
throw FlowException("Manual payment amount must be in FiatCurrency") | ||
if (obligation.settlementMethod == null || obligation.settlementMethod !is ManualSettlement) | ||
throw FlowException("settlementMethod of ManualSettlement must be provided for manual payment") | ||
sleep(Duration.ofMillis(1)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the sleep for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure. Left over from my copying MakeSWIFTPayment. Can remove.
if (obligation.settlementMethod == null || obligation.settlementMethod !is ManualSettlement) | ||
throw FlowException("settlementMethod of ManualSettlement must be provided for manual payment") | ||
sleep(Duration.ofMillis(1)) | ||
return ManualPayment((obligation.payments.size + 1).toString(), amount as Amount<FiatCurrency>, PaymentStatus.SENT) as Payment<T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The payment reference is just an int for now ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just used something to make a unique identifier for referencing later when payments are updated. Not sure what it's used for. Didn't see a way to set it with user input in the flow.
manual/src/main/kotlin/com.r3.corda.finance.manual/contract/DummyContract.kt
Show resolved
Hide resolved
@InitiatedBy(Initiator::class) | ||
class Responder(val otherFlow: FlowSession) : FlowLogic<WireTransaction>() { | ||
@Suspendable | ||
override fun call(): WireTransaction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually return the signed transaction here, so you have the signatures, if you need them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, here i think i returned wire transaction so that it was rendered in the shell (which was a bit of a hack) :)
@yikailim93 I think manual settlement is quite useful if you need to settle something off ledger but the rail isn't yet supported. If you trust your counterpart, you can compromise some automation and assurance to handle settlements. Cheers |
@yikailim93 Yes we created manual settlement because we need it for our client who do off ledger settlements by writing checks, etc. The obligee can manually verify the payment was received. At the moment, we have no way of automatically verifying a payment was made. |
There's already contract verification code for cancelling an obligation, or did you mean something else? |
Thank you both for the reply.
@countfloyd is your CorDapp currently up and running? And if I may ask, did you have to make a lot of changes to the cordapp/cordapp-contracts-states/oracle modules (or any other module) in order to integrate your manual settlement module? Also, are the source files in your manual settlement module the only/main files you have created to achieve your objective? Asking all these because I'm currently trying to develop my own settler as well but is facing a lot of roadblocks. Would appreciate if you could shed some light on this corda-settler. |
Sorry, my bad - I think I even added it. Doh! |
@yikailim93 Yes our app is running in private test but not in production. All I really did was add my own ManualSettlement class and ManualPayment as well as a MakeManualPayment flow. I don't use the oracle at all because we have no way to automatically verifying that a payment was made. Instead, I made a UpdatePaymentStatusManually flow so that the obligee could verify that the payment was received. The manual module in Corda-settler was all I added to make obligations work for me, yes. |
…, and other small changes suggested by Roger
…, and other small changes suggested by Roger
New changes for review:
|
Thank you @countfloyd! This information is very helpful. May I ask if you can share the commands you ran on the nodes' terminal for the process from creating an obligation up until settlement? This will solely be for demonstration purposes. Also, if I may add on, I was trying to run the corda-settler repo that you have uploaded on your profile. I encountered the error below when running gradlew clean deployNodes, do you have any idea what went wrong?
PS: I'm really sorry to keep bothering you here, I've been trying to develop my own settler for the past 2 months but kept getting errors and I'm still no where near completing my cordapp. Really hope that you wouldn't mind me asking all the questions. |
@countfloyd I've tried to run the tests locally but none of them pass:
Cheers |
@yikailim93 can you please stop asking support questions in this PR? Either go on to slack and ask a question, use stack over flow or submit a github issue. Me or others will be happy to help you in those places. Cheers |
@roger3cev okay, sorry for the inconvenience caused. |
@yikailim93 no worries - is also better for you to ask questions in those places. There's more people to help :) |
@roger3cev Hmmm weird. The tests passed for me. Although I only ran them from my IDE. I'll check it out along with your other issues. Won't be able to work on it until next week. Thanks for your review. |
@roger3cev, addressed the issues you outlined. Just wondering what I need to run the SWIFT unit tests. README says I need to email you for API key and I need a swift.pem file? Can you email me what I need? XRP tests all run successfully now. Thanks. |
…ligation, getting tests to run successfully
@countfloyd dont worry about the SWIFT tests - I'll sort those out. Cheers! |
This looks great - good to merge! |
Thanks for the contribution @countfloyd ! |
Yes, thanks @countfloyd - great work and much appreciated by all. |
My pleasure, thanks for the work reviewing this. |
This PR is a result of the work I did working Corda-settler into our Cordapp.
The main change is the addition of a manual settlement rail. Since the oracle can't be used to verify manual payments, I added a flow to change a payment status. Also, made the settlementOracle field optional and the oracle will not be consulted if it's null
Updated deprecated flow constructors to use 4.0 constructors
Fixed some warnings
Updated kittinunf.fuel to latest version
I've been testing quite extensively (except for the oracle, swift and ripple modules). Still need to add some unit test for the manual module. Hope this PR isn't too big :)