Skip to content

Commit 28b9260

Browse files
authored
Merge pull request #5 from QuarkChain/test
add test
2 parents a56c391 + b04068f commit 28b9260

3 files changed

Lines changed: 256 additions & 0 deletions

File tree

contracts/app/Bridge.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,14 @@ contract BridgeDestination {
117117
ownerMap[key] = msg.sender;
118118
}
119119

120+
function verifyStateRoot(bytes32 stateRoot, bytes32[] memory stateRootProof)
121+
internal
122+
pure
123+
virtual
124+
{
125+
assert(false);
126+
}
127+
120128
function withdraw(
121129
TransferKey memory tkey,
122130
bytes32[] memory stateRootProof,
@@ -126,6 +134,7 @@ contract BridgeDestination {
126134
bytes32[] memory recordProof
127135
) public {
128136
if (!validatedStateRoots[stateRoot]) {
137+
verifyStateRoot(stateRoot, stateRootProof);
129138
// TODO: prove stateRoot is in stateRootProof
130139
validatedStateRoots[stateRoot] = true;
131140
}

contracts/app/TestBridge.sol

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import "./Bridge.sol";
5+
6+
contract TestBridgeDestination is BridgeDestination {
7+
function verifyStateRoot(bytes32 stateRoot, bytes32[] memory stateRootProof)
8+
internal
9+
pure
10+
override
11+
{
12+
// pass
13+
}
14+
}

test/bridge-test.js

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
const { web3 } = require("hardhat");
2+
const { expect } = require("chai");
3+
const { ethers } = require("hardhat");
4+
5+
function calc_root_hash(nodes) {
6+
hl = nodes.map((x) => web3.utils.soliditySha3(...x));
7+
8+
if (hl.length == 0) {
9+
return "0x0000000000000000000000000000000000000000000000000000000000000000";
10+
}
11+
12+
while (hl.length > 1) {
13+
let nhl = [];
14+
for (let i = 0; i < hl.length; i += 2) {
15+
nhl.push(
16+
web3.utils.soliditySha3(
17+
{ t: "uint256", v: hl[i] },
18+
{
19+
t: "uint256",
20+
v:
21+
i + 1 < hl.length
22+
? hl[i + 1]
23+
: "0x0000000000000000000000000000000000000000000000000000000000000000",
24+
}
25+
)
26+
);
27+
}
28+
29+
hl = nhl;
30+
}
31+
32+
return hl[0];
33+
}
34+
35+
function get_update_proof(nodes, idx) {
36+
hl = nodes.map((x) => web3.utils.soliditySha3(...x));
37+
if (idx == hl.length) {
38+
// append
39+
hl.push(
40+
"0x0000000000000000000000000000000000000000000000000000000000000000"
41+
);
42+
}
43+
let proof = [];
44+
45+
while (hl.length > 1 || idx != 0) {
46+
nidx = Math.floor(idx / 2) * 2;
47+
if (nidx == idx) {
48+
nidx += 1;
49+
}
50+
51+
if (nidx < hl.length) {
52+
proof.push(hl[nidx]);
53+
}
54+
55+
let nhl = [];
56+
for (let i = 0; i < hl.length; i += 2) {
57+
let left = hl[i];
58+
let right =
59+
i + 1 < hl.length
60+
? hl[i + 1]
61+
: "0x0000000000000000000000000000000000000000000000000000000000000000";
62+
nhl.push(web3.utils.soliditySha3(left, right));
63+
}
64+
65+
hl = nhl;
66+
idx = Math.floor(idx / 2);
67+
}
68+
69+
return proof;
70+
}
71+
72+
function get_append_proof(nodes) {
73+
return get_update_proof(nodes, nodes.length);
74+
}
75+
76+
describe("Bridge", function () {
77+
it("simple bridge withdraw test", async function () {
78+
const Tree = await ethers.getContractFactory("DynamicMerkleTree");
79+
const tree = await Tree.deploy();
80+
await tree.deployed();
81+
82+
const BridgeSource = await ethers.getContractFactory("BridgeSource", {
83+
libraries: {
84+
DynamicMerkleTree: tree.address,
85+
},
86+
});
87+
const bridgeSrc = await BridgeSource.deploy();
88+
await bridgeSrc.deployed();
89+
90+
const Token = await ethers.getContractFactory("TestERC20");
91+
const tokenSrc = await Token.deploy();
92+
await tokenSrc.deployed();
93+
94+
const tokenDst = await Token.deploy();
95+
await tokenDst.deployed();
96+
97+
const BridgeDestination = await ethers.getContractFactory(
98+
"TestBridgeDestination",
99+
{
100+
libraries: {
101+
DynamicMerkleTree: tree.address,
102+
},
103+
}
104+
);
105+
const bridgeDst = await BridgeDestination.deploy();
106+
await bridgeDst.deployed();
107+
108+
const [acc0, acc1, acc2, acc3, acc4] = await ethers.getSigners();
109+
110+
await tokenSrc.mint(acc0.address, 10000);
111+
await tokenSrc.approve(bridgeSrc.address, 10000);
112+
await tokenDst.mint(bridgeDst.address, 1000);
113+
114+
let nodes = [];
115+
116+
await bridgeSrc.withdraw(
117+
tokenSrc.address,
118+
{
119+
tokenAddress: tokenDst.address,
120+
destination: acc1.address,
121+
amount: 1000,
122+
startTime: 0,
123+
feeRampup: 0,
124+
},
125+
get_append_proof(nodes)
126+
);
127+
128+
await bridgeDst.withdraw(
129+
{
130+
transferData: {
131+
tokenAddress: tokenDst.address,
132+
destination: acc1.address,
133+
amount: 1000,
134+
startTime: 0,
135+
feeRampup: 0,
136+
},
137+
transferId: 0,
138+
},
139+
[],
140+
await bridgeSrc.stateRoot(),
141+
bridgeSrc.address,
142+
1,
143+
get_update_proof(nodes, 0)
144+
);
145+
});
146+
147+
it("simple bridge buy then withdraw test", async function () {
148+
const Tree = await ethers.getContractFactory("DynamicMerkleTree");
149+
const tree = await Tree.deploy();
150+
await tree.deployed();
151+
152+
const BridgeSource = await ethers.getContractFactory("BridgeSource", {
153+
libraries: {
154+
DynamicMerkleTree: tree.address,
155+
},
156+
});
157+
const bridgeSrc = await BridgeSource.deploy();
158+
await bridgeSrc.deployed();
159+
160+
const Token = await ethers.getContractFactory("TestERC20");
161+
const tokenSrc = await Token.deploy();
162+
await tokenSrc.deployed();
163+
164+
const tokenDst = await Token.deploy();
165+
await tokenDst.deployed();
166+
167+
const BridgeDestination = await ethers.getContractFactory(
168+
"TestBridgeDestination",
169+
{
170+
libraries: {
171+
DynamicMerkleTree: tree.address,
172+
},
173+
}
174+
);
175+
const bridgeDst = await BridgeDestination.deploy();
176+
await bridgeDst.deployed();
177+
178+
const [acc0, acc1, acc2, acc3, acc4] = await ethers.getSigners();
179+
180+
await tokenSrc.mint(acc0.address, 10000);
181+
await tokenSrc.approve(bridgeSrc.address, 10000);
182+
await tokenDst.mint(bridgeDst.address, 1000);
183+
184+
let nodes = [];
185+
186+
await bridgeSrc.withdraw(
187+
tokenSrc.address,
188+
{
189+
tokenAddress: tokenDst.address,
190+
destination: acc1.address,
191+
amount: 1000,
192+
startTime: 0,
193+
feeRampup: 0,
194+
},
195+
get_append_proof(nodes)
196+
);
197+
198+
await tokenDst.mint(acc2.address, 1000);
199+
await tokenDst.connect(acc2).approve(bridgeDst.address, 1000);
200+
await bridgeDst.connect(acc2).buy({
201+
transferData: {
202+
tokenAddress: tokenDst.address,
203+
destination: acc1.address,
204+
amount: 1000,
205+
startTime: 0,
206+
feeRampup: 0,
207+
},
208+
transferId: 0,
209+
});
210+
211+
expect(await tokenDst.balanceOf(acc1.address)).to.equal(1000);
212+
213+
await bridgeDst.connect(acc2).withdraw(
214+
{
215+
transferData: {
216+
tokenAddress: tokenDst.address,
217+
destination: acc1.address,
218+
amount: 1000,
219+
startTime: 0,
220+
feeRampup: 0,
221+
},
222+
transferId: 0,
223+
},
224+
[],
225+
await bridgeSrc.stateRoot(),
226+
bridgeSrc.address,
227+
1,
228+
get_update_proof(nodes, 0)
229+
);
230+
231+
expect(await tokenDst.balanceOf(acc2.address)).to.equal(1000);
232+
});
233+
});

0 commit comments

Comments
 (0)