Skip to content

Commit f581cf5

Browse files
authored
Merge pull request #200 from knarayan/main
Asset transfer inteop mode implementation for Corda
2 parents c74bf89 + fe846af commit f581cf5

File tree

93 files changed

+6384
-283
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+6384
-283
lines changed

.github/workflows/test_asset-exchange-corda.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ jobs:
255255
./scripts/get-cordapps.sh || mv github.main.properties github.properties
256256
257257
cat github.properties
258-
cp github.properties ../../../samples/corda/corda-simple-application/
258+
cp github.properties ../../../samples/corda/corda-simple-application/
259259
working-directory: tests/network-setups/corda
260260

261261
- name: Generate github.properties (else)
@@ -266,7 +266,7 @@ jobs:
266266
echo "password=${{ secrets.GITHUB_TOKEN }}" >> github.properties
267267
echo "url=https://maven.pkg.github.com/hyperledger-labs/weaver-dlt-interoperability" >> github.properties
268268
cat github.properties
269-
cp github.properties ../../../samples/corda/corda-simple-application/
269+
cp github.properties ../../../samples/corda/corda-simple-application/
270270
working-directory: tests/network-setups/corda
271271

272272
# CORDA NETWORK

.github/workflows/test_asset-transfer.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ jobs:
254254
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
255255
256256
# FABRIC1 - FABRIC2
257-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond --pledge-id=$CID --param=bond01:a03 &> tmp.out
257+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a03 &> tmp.out
258258
tail -n 1 tmp.out | grep "Called Function ClaimRemoteAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
259259
cat tmp.out
260260
@@ -272,11 +272,11 @@ jobs:
272272
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
273273
sleep 20
274274
275-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond --pledge-id=$CID --param=bond01:a04 &> tmp.out
275+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out
276276
tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS"
277277
cat tmp.out
278278
279-
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=bond --pledge-id=$CID --param=bond01:a04 &> tmp.out
279+
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out
280280
tail -n 1 tmp.out | grep "Called Function ReclaimAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
281281
cat tmp.out
282282
@@ -312,7 +312,7 @@ jobs:
312312
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
313313
314314
# FABRIC1 - FABRIC2
315-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token --pledge-id=$CID --param=token1:50 &> tmp.out
315+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:50 &> tmp.out
316316
tail -n 1 tmp.out | grep "Called Function ClaimRemoteTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
317317
cat tmp.out
318318
@@ -330,11 +330,11 @@ jobs:
330330
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
331331
sleep 20
332332
333-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token --pledge-id=$CID --param=token1:100 &> tmp.out
333+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out
334334
tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS"
335335
cat tmp.out
336336
337-
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=token --pledge-id=$CID --param=token1:100 &> tmp.out
337+
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out
338338
tail -n 1 tmp.out | grep "Called Function ReclaimTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
339339
cat tmp.out
340340
@@ -622,7 +622,7 @@ jobs:
622622
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
623623
624624
# FABRIC1 - FABRIC2
625-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond --pledge-id=$CID --param=bond01:a03 &> tmp.out
625+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a03 &> tmp.out
626626
tail -n 1 tmp.out | grep "Called Function ClaimRemoteAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
627627
cat tmp.out
628628
@@ -640,11 +640,11 @@ jobs:
640640
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
641641
sleep 20
642642
643-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond --pledge-id=$CID --param=bond01:a04 &> tmp.out
643+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out
644644
tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS"
645645
cat tmp.out
646646
647-
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=bond --pledge-id=$CID --param=bond01:a04 &> tmp.out
647+
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=bond.fabric --pledge-id=$CID --param=bond01:a04 &> tmp.out
648648
tail -n 1 tmp.out | grep "Called Function ReclaimAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
649649
cat tmp.out
650650
@@ -680,7 +680,7 @@ jobs:
680680
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
681681
682682
# FABRIC1 - FABRIC2
683-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token --pledge-id=$CID --param=token1:50 &> tmp.out
683+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:50 &> tmp.out
684684
tail -n 1 tmp.out | grep "Called Function ClaimRemoteTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
685685
cat tmp.out
686686
@@ -698,11 +698,11 @@ jobs:
698698
CID=$(cat tmp.out | grep "Asset pledged with ID " | sed -e 's/Asset pledged with ID //')
699699
sleep 20
700700
701-
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token --pledge-id=$CID --param=token1:100 &> tmp.out
701+
./bin/fabric-cli asset transfer claim --source-network=network1 --dest-network=network2 --user=bob --owner=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out
702702
tail -n 1 tmp.out | grep "cannot claim asset with pledgeId $CID as the expiry time has elapsed" && COUNT=$(( COUNT + 1 )) && echo "PASS"
703703
cat tmp.out
704704
705-
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=token --pledge-id=$CID --param=token1:100 &> tmp.out
705+
./bin/fabric-cli asset transfer reclaim --source-network=network1 --user=alice --type=token.fabric --pledge-id=$CID --param=token1:100 &> tmp.out
706706
tail -n 1 tmp.out | grep "Called Function ReclaimTokenAsset. With Args: $CID" && COUNT=$(( COUNT + 1 )) && echo "PASS"
707707
cat tmp.out
708708
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
name=Interop Protos
22
group=com.weaver
3-
version=1.2.4-alpha.7
3+
version=1.2.4-alpha.8
44
kotlin.incremental=false

core/drivers/corda-driver/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ buildscript {
1010
ext.corda_version = "4.8.4"
1111
ext.corda_core_version = "4.8.4"
1212
ext.arrow_version = "0.10.4"
13-
ext.weaver_version = "1.2.4-alpha.+"
13+
ext.weaver_version = "1.2.4-alpha.+" // works for any version 1.2.4-alpha.*
1414

1515
repositories {
1616
mavenCentral()
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
kotlin.code.style=official
22
name=corda-driver
33
group=com.weaver.corda.driver
4-
version=1.2.4-alpha.7
5-
kotlin.incremental=false
4+
version=1.2.4-alpha.8
5+
kotlin.incremental=false

core/network/corda-interop-app/constants.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ platformVersion=10
1010
slf4jVersion=1.7.25
1111
nettyVersion=4.1.22.Final
1212
arrowVersion=0.10.4
13+
1314
weaverVersion=1.2.4-alpha.+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
name=Interoperability CorDapp
22
group=com.weaver.corda.app.interop
3-
version=1.2.4-alpha.7
3+
version=1.2.4-alpha.8
44
kotlin.incremental=false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/*
2+
* Copyright IBM Corp. All Rights Reserved.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package com.weaver.corda.app.interop.contracts
8+
9+
import com.weaver.corda.app.interop.states.AssetPledgeState
10+
import com.weaver.corda.app.interop.states.AssetClaimStatusState
11+
import com.weaver.corda.app.interop.states.NetworkIdState
12+
import net.corda.core.contracts.CommandData
13+
import net.corda.core.contracts.Contract
14+
import net.corda.core.contracts.requireSingleCommand
15+
import net.corda.core.contracts.requireThat
16+
import net.corda.core.contracts.StaticPointer
17+
import net.corda.core.transactions.LedgerTransaction
18+
import java.time.Instant
19+
import java.util.*
20+
21+
/**
22+
* AssetTransferContract defines the rules for managing a [AssetPledgeState].
23+
*
24+
*/
25+
class AssetTransferContract : Contract {
26+
companion object {
27+
// Used to identify our contract when building a transaction.
28+
const val ID = "com.weaver.corda.app.interop.contracts.AssetTransferContract"
29+
}
30+
31+
/**
32+
* A transaction is valid if the verify() function of the contract for any of the transaction's
33+
* input and output states does not throw an exception.
34+
*/
35+
override fun verify(tx: LedgerTransaction) {
36+
val command = tx.commands.requireSingleCommand<Commands>()
37+
when (command.value) {
38+
is Commands.Pledge -> requireThat {
39+
"There should be one input state." using (tx.inputs.size == 1)
40+
"There should be one output state." using (tx.outputs.size == 1)
41+
"The output state should be of type AssetPledgeState." using (tx.outputs[0].data is AssetPledgeState)
42+
43+
// Get the Asset Pledge State
44+
val pledgeState = tx.outputs[0].data as AssetPledgeState
45+
46+
// Check if output belong to this contract
47+
"Output state should belong to this contract" using (tx.outputs[0].contract.equals(ID))
48+
49+
// Check if timeout is beyond current time
50+
val expiryTime = Instant.ofEpochSecond(pledgeState.expiryTimeSecs)
51+
"AssetPledgeState.expiryTimeSecs is after current time." using (expiryTime.isAfter(Instant.now()))
52+
53+
// Check if the asset owner is the locker
54+
val inputState = tx.inputs[0].state.data
55+
"Locker must be the owner of pledged asset" using inputState.participants.containsAll(listOf(pledgeState.locker))
56+
57+
// Check if asset consumed (input state) is the same used in pledge
58+
val assetPointer = StaticPointer(tx.inputs[0].ref, tx.inputs[0].state.data.javaClass)
59+
"Asset consumed should be the one used in pledge." using (assetPointer.equals(pledgeState.assetStatePointer))
60+
61+
// Check if the locker is a signer
62+
val requiredSigners = pledgeState.participants.map { it.owningKey }
63+
"The required signers of the transaction must include the locker." using (command.signers.containsAll(requiredSigners))
64+
65+
val inReferences = tx.referenceInputRefsOfType<NetworkIdState>()
66+
"There should be a single reference input network id." using (inReferences.size == 1)
67+
68+
val validNetworkIdState = inReferences.get(0).state.data
69+
"AssetPledgeState.localNetwokId must match with the networkId of current network." using (pledgeState.localNetworkId.equals(validNetworkIdState.networkId))
70+
}
71+
is Commands.ClaimRemoteAsset -> requireThat {
72+
"There should be no input state." using (tx.inputs.size == 0)
73+
"There should be two output states." using (tx.outputs.size == 2)
74+
"One of the output states should be of type AssetClaimStatusState." using (tx.outputsOfType<AssetClaimStatusState>().size == 1)
75+
76+
// Check if output state [AssetClaimStatusState] belongs to this contract
77+
"Output state should belong to this contract" using (tx.outputs[1].contract.equals(ID))
78+
79+
// Get the input asset pledge state
80+
val claimState = tx.outputs[1].data as AssetClaimStatusState
81+
82+
val inReferences = tx.referenceInputRefsOfType<NetworkIdState>()
83+
"There should be a single reference input network id." using (inReferences.size == 1)
84+
val validNetworkIdState = inReferences.get(0).state.data
85+
86+
"AssetClaimStatusState.localNetwokID must match with the networkId of current network." using (claimState.localNetworkID.equals(validNetworkIdState.networkId))
87+
88+
// Check if timeWindow <= expiryTime
89+
val untilTime = tx.timeWindow!!.untilTime!!
90+
val expiryTime = Instant.ofEpochSecond(claimState.expiryTimeSecs)
91+
"TimeWindow to claim pledged remote asset should be before expiry time." using
92+
(untilTime.isBefore(expiryTime) || untilTime.equals(expiryTime))
93+
94+
// Check if the owner of the asset in the importing network after asset claim is the recipient
95+
val outputAssetState = tx.outputs[0].data
96+
"Recipient must be the owner of claimed asset." using (outputAssetState.participants.containsAll(listOf(claimState.recipient)))
97+
98+
// Check if the recipient is a signer
99+
val requiredSigners = claimState.participants.map { it.owningKey }
100+
"The required signers of the transaction must include the recipient." using (command.signers.containsAll(requiredSigners))
101+
}
102+
is Commands.ReclaimPledgedAsset -> requireThat {
103+
"There should be one input state." using (tx.inputs.size == 1)
104+
"The input state should be of type AssetPledgeState." using (tx.inputs[0].state.data is AssetPledgeState)
105+
"There should be one output state." using (tx.outputs.size == 1)
106+
107+
// Get the input asset pledge state
108+
val pledgeState = tx.inputs[0].state.data as AssetPledgeState
109+
110+
// Check if timeWindow > expiryTime
111+
val fromTime = tx.timeWindow!!.fromTime!!
112+
"TimeWindow for reclaim pledged asset should be after expiry time." using (fromTime.isAfter(Instant.ofEpochSecond(pledgeState.expiryTimeSecs)))
113+
114+
// Check if the asset owner is the locker
115+
val outputState = tx.outputs[0].data
116+
"Locker must be the owner of pledged asset" using outputState.participants.containsAll(listOf(pledgeState.locker))
117+
118+
// Verify if locker is the signer
119+
val requiredSigners = listOf(pledgeState.locker.owningKey)
120+
"The required signers of the transaction must include the locker." using (command.signers.containsAll(requiredSigners))
121+
122+
val inReferences = tx.referenceInputRefsOfType<NetworkIdState>()
123+
"There should be a single reference input network id." using (inReferences.size == 1)
124+
val validNetworkIdState = inReferences.get(0).state.data
125+
126+
"LocalNetwokId must match with the networkId of current network." using (pledgeState.localNetworkId.equals(validNetworkIdState.networkId))
127+
}
128+
}
129+
}
130+
131+
/**
132+
* Commands are used to indicate the intent of a transaction.
133+
* Commands for [AssetTransferContract] are:
134+
* - Pledge
135+
* - ReclaimPledgedAsset
136+
* - ClaimRemoteAsset
137+
*/
138+
interface Commands : CommandData {
139+
class Pledge : Commands
140+
class ReclaimPledgedAsset : Commands
141+
class ClaimRemoteAsset : Commands
142+
}
143+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright IBM Corp. All Rights Reserved.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package com.weaver.corda.app.interop.contracts
8+
9+
import com.weaver.corda.app.interop.states.NetworkIdState
10+
import net.corda.core.contracts.CommandData
11+
import net.corda.core.contracts.Contract
12+
import net.corda.core.contracts.Requirements.using
13+
import net.corda.core.contracts.requireSingleCommand
14+
import net.corda.core.contracts.requireThat
15+
import net.corda.core.transactions.LedgerTransaction
16+
17+
/**
18+
* NetworkIdStateContract defines the rules for managing [NetworkIdState].
19+
*
20+
* For a new [NetworkIdState] to be created, a transaction is required that fulfills the following:
21+
* - The Create() command with the public keys of all the participants.
22+
* - No input states.
23+
* - One output state of type [NetworkIdState].
24+
*/
25+
class NetworkIdStateContract : Contract {
26+
companion object {
27+
// Used to identify our contract when building a transaction.
28+
const val ID = "com.weaver.corda.app.interop.contracts.NetworkIdStateContract"
29+
}
30+
/**
31+
* The verify() function determines a transaction is valid if it does not throw and exception.
32+
* It takes a ledger transaction that represents a state transition, and ensures the inputs/outputs/commands make sense.
33+
*/
34+
override fun verify(tx: LedgerTransaction) {
35+
val command = tx.commands.requireSingleCommand<Commands>()
36+
when(command.value) {
37+
is Commands.Create -> requireThat {
38+
"There should be no input states" using (tx.inputs.isEmpty())
39+
"There should be one output state" using (tx.outputs.size == 1)
40+
"The output state should be of type NetworkIdState" using (tx.outputs[0].data is NetworkIdState)
41+
val participantKeys = tx.outputs[0].data.participants.map { it.owningKey }
42+
"The required signers of the transaction must include all participants" using (command.signers.containsAll(participantKeys))
43+
}
44+
}
45+
}
46+
47+
/**
48+
* Commands are used to indicate the intent of a transaction.
49+
* Commands for [NetworkIdState] are:
50+
* - Create
51+
*/
52+
interface Commands : CommandData {
53+
class Create : Commands
54+
}
55+
}

0 commit comments

Comments
 (0)