Skip to content

Commit 3fe57b3

Browse files
authored
Merge pull request #183 from dhinakaran2705/main
Core network interop contracts for Besu for exchanging ERC20 tokens and a simpleasset application
2 parents cc5b79b + 5d6769a commit 3fe57b3

File tree

14 files changed

+683
-2
lines changed

14 files changed

+683
-2
lines changed
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
pragma solidity ^0.8.8;
4+
5+
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6+
7+
/**
8+
* Hashed Timelock Contract on Fungible Assets in an Ethereum network (Support only for ERC20 tokens right now)
9+
**/
10+
11+
contract InteroperationBaseClassERC20 {
12+
13+
mapping (bytes32 => LockContract) public lockContracts;
14+
15+
struct LockContract {
16+
address sender;
17+
address receiver;
18+
address assetContract;
19+
uint256 amount;
20+
bytes32 hashLock;
21+
uint256 expirationTime;
22+
uint8 status;
23+
}
24+
25+
uint8 constant UNUSED = 0;
26+
uint8 constant LOCKED = 1;
27+
28+
event Lock(
29+
address indexed sender,
30+
address indexed receiver,
31+
address assetContract,
32+
uint256 amount,
33+
bytes32 hashLock,
34+
uint256 expirationTime,
35+
bytes32 lockContractId
36+
);
37+
38+
event Claim(
39+
address indexed sender,
40+
address indexed receiver,
41+
bytes32 indexed lockContractId,
42+
bytes32 hashLock,
43+
bytes32 preimage
44+
);
45+
46+
event Unlock(
47+
address indexed sender,
48+
address indexed receiver,
49+
bytes32 indexed lockContractId
50+
);
51+
52+
53+
// The sender locks a fungible asset with a hash lock and an expiry time
54+
function lockFungibleAsset(
55+
address receiver,
56+
address assetContract,
57+
uint256 amount,
58+
bytes32 hashLock,
59+
uint256 expirationTime
60+
)
61+
external
62+
returns (bytes32 lockContractId)
63+
{
64+
address sender = msg.sender;
65+
66+
// Checking the validity of the input parameters
67+
require(amount > 0, "Amount should be greater than zero");
68+
require(ERC20(assetContract).allowance(sender, address(this)) >= amount, "Allowance of assets from the sender for the lock contract must be greater than the amount to be locked");
69+
require(expirationTime > block.timestamp, "Expiration time should be in the future");
70+
71+
// The identity of the lock contract is a hash of all the relevant parameters that will uniquely identify the contract
72+
lockContractId = sha256(
73+
abi.encodePacked(
74+
sender,
75+
receiver,
76+
assetContract,
77+
amount,
78+
hashLock,
79+
expirationTime
80+
)
81+
);
82+
83+
require(lockContracts[lockContractId].status == UNUSED, "An active lock contract already exists with the same parameters");
84+
85+
// Locking amount by transfering them to the lockContract
86+
bool transferStatus = ERC20(assetContract).transferFrom(sender, address(this), amount);
87+
require(transferStatus == true, "ERC20 transferFrom failed from the sender to the lockContract");
88+
89+
lockContracts[lockContractId] = LockContract(
90+
sender,
91+
receiver,
92+
assetContract,
93+
amount,
94+
hashLock,
95+
expirationTime,
96+
LOCKED
97+
);
98+
99+
emit Lock(
100+
sender,
101+
receiver,
102+
assetContract,
103+
amount,
104+
hashLock,
105+
expirationTime,
106+
lockContractId
107+
);
108+
}
109+
110+
111+
// The receiver claims the ownership of an asset locked for them once they obtain the preimage of the hashlock
112+
function claimFungibleAsset(bytes32 lockContractId, bytes32 preimage)
113+
external
114+
returns (bool)
115+
{
116+
LockContract storage c = lockContracts[lockContractId];
117+
118+
// Check the validity of the claim
119+
require(c.status == LOCKED, "lockContract is not active");
120+
require(block.timestamp < c.expirationTime, "lockContract has expired");
121+
require(c.hashLock == sha256(abi.encodePacked(preimage)),"Invalid preimage, its hash does not equal the hashLock");
122+
123+
bool transferStatus = ERC20(c.assetContract).transfer(c.receiver, c.amount);
124+
require(transferStatus == true, "ERC20 transfer failed from the lockContract to the receiver");
125+
126+
emit Claim(
127+
c.sender,
128+
c.receiver,
129+
lockContractId,
130+
c.hashLock,
131+
preimage
132+
);
133+
134+
return true;
135+
}
136+
137+
138+
// Unlocking and reclaiming a locked asset for the sender after the expiration time. Can be called by anyone, not just the sender.
139+
function unlockFungibleAsset(bytes32 lockContractId)
140+
external
141+
returns (bool)
142+
{
143+
LockContract storage c = lockContracts[lockContractId];
144+
145+
// Validation checks
146+
require(c.status == LOCKED, "There is no active lockContract with the specified ID");
147+
require(c.sender != address(0), "Sender address is invalid");
148+
require(block.timestamp >= c.expirationTime, "Lock contract has expired");
149+
150+
bool transferStatus = ERC20(c.assetContract).transfer(c.sender, c.amount);
151+
require(transferStatus == true, "ERC20 transfer failed from the lockContract back to the sender");
152+
153+
emit Unlock(
154+
c.sender,
155+
c.receiver,
156+
lockContractId
157+
);
158+
159+
return true;
160+
}
161+
162+
163+
// Function to check if there is an active contract with the input lockContractId.
164+
function isFungibleAssetLocked(bytes32 lockContractId)
165+
external
166+
returns (bool)
167+
{
168+
LockContract storage c = lockContracts[lockContractId];
169+
170+
bool lockContractStatus;
171+
if ( c.status == LOCKED ){
172+
lockContractStatus = true;
173+
} else {
174+
lockContractStatus = false;
175+
}
176+
177+
return lockContractStatus;
178+
}
179+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
build
2+
node_modules
3+
contracts/manageAsset.sol
4+
package-lock.json

samples/besu/simpleasset/Makefile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
.PHONY: deploy-contracts
2+
deploy-contracts: deploy-contract-network1 deploy-contract-network2
3+
4+
.PHONY: deploy-contract-network1
5+
deploy-contract-network1:
6+
BESU_NETWORK_HOST=localhost BESU_NETWORK_PORT=8545 npm run deploy-contract
7+
8+
.PHONY: deploy-contract-network2
9+
deploy-contract-network2:
10+
BESU_NETWORK_HOST=localhost BESU_NETWORK_PORT=9544 npm run deploy-contract
11+
12+
.PHONY: clean-run
13+
clean-run:
14+
npm run clean-run
15+
16+
.PHONY: clean
17+
clean:
18+
npm run clean

samples/besu/simpleasset/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!--
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: CC-BY-4.0
5+
-->
6+
# A Sample Application for Asset Exchange across Two Besu Networks using HTLC
7+
8+
## Deploy contracts
9+
The following command deploys the contracts on the two test networks:
10+
```
11+
make deploy-contracts
12+
```
13+
This internally does the following:
14+
- copies the core network contracts to the contracts folder in the truffle application.
15+
* In future, this should be replaced by exporting the core contracts as an npm or EthPM package and the app importing this package.
16+
* The support is also only for ERC-20 tokens right now. This will be extended to ERC-721 soon. And in this future for any asset type.
17+
- updates truffle-config.js based on the environment variables BESU\_NETWORK\_HOST and BESU\_NETWORK\_PORT
18+
- installs the missing packages
19+
- compiles the contracts and migrates them to both the test networks
20+
21+
## Run the asset exchange application
22+
The sample application will have Alice transfer AliceERC20 tokens in Network 1 to Bob atomically with Bob transfering an equivalent amount of BobERC20 tokens to Alice in Network 2.
23+
```
24+
node app/AssetExchangeERC20.js
25+
```
26+
27+
## Troubleshoot
28+
- Check if truffle is installed: npm install -g truffle
29+
30+
- Pay attention to the number of tokens initally owned by Alice and Bob in Networks 1 and 2 respectively, if there are other applications that use/spend their tokens in parallel to this app. Ensure that there are sufficient tokens in their accounts to lock.

0 commit comments

Comments
 (0)