Skip to content

Commit

Permalink
finish final tests
Browse files Browse the repository at this point in the history
  • Loading branch information
WuBruno committed Nov 24, 2023
1 parent d42989c commit 12d3423
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 41 deletions.
2 changes: 1 addition & 1 deletion products/bridge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ The MVP bridge will run on a gossip network with validators managed by Zilliqa

- [ ] **Smart Contracts** - on hardhat (E2E testing & deployment) + foundry (Unit testing + fuzzing)
- [ ] Integrate foundry to support effective unit testing on contracts
- [ ] Finish remaining TODO tests
- [x] Finish remaining TODO tests
- [x] Update error handling on contracts
- [ ] Write deployment scripts
- [ ] Support CREATE2
Expand Down
63 changes: 49 additions & 14 deletions products/bridge/smart-contracts/contracts/Test.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ contract Twin is Initializable, Bridged, BridgedTwin {
readonly,
this.finish.selector
);
console.log("start()", nonce);
}

event Succeeded(uint);
Expand All @@ -29,7 +28,6 @@ contract Twin is Initializable, Bridged, BridgedTwin {
bytes calldata res,
uint nonce
) external onlyRelayer {
console.log("finish()", nonce);
if (success) {
uint num = abi.decode(res, (uint));
emit Succeeded(num);
Expand All @@ -40,15 +38,39 @@ contract Twin is Initializable, Bridged, BridgedTwin {
}
}

function startSum(address target, uint num, bool readonly) external {
relay(
twinChainId(),
target,
abi.encodeWithSignature("testSum(uint256)", num),
readonly,
this.finishSum.selector
);
}

function finishSum(
bool success,
bytes calldata res,
uint nonce
) external onlyRelayer {
if (success) {
uint num = abi.decode(res, (uint));
emit Succeeded(num);
} else {
bytes4(res[:4]);
bytes memory err = bytes(res[4:]);
emit Failed(abi.decode(err, (string)));
}
}

function startNoReturn(address target, uint num, bool readonly) external {
uint nonce = relay(
relay(
twinChainId(),
target,
abi.encodeWithSignature("testNoReturn(uint256)", num),
readonly,
this.finishNoReturn.selector
);
console.log("start()", nonce);
}

event SucceededNoReturn();
Expand All @@ -61,7 +83,7 @@ contract Twin is Initializable, Bridged, BridgedTwin {
if (success) {
emit SucceededNoReturn();
} else {
bytes4 sig = bytes4(res[:4]);
bytes4(res[:4]);
bytes memory err = bytes(res[4:]);
emit Failed(abi.decode(err, (string)));
}
Expand All @@ -72,7 +94,7 @@ contract Twin is Initializable, Bridged, BridgedTwin {
uint num,
bool readonly
) external {
uint nonce = relay(
relay(
twinChainId(),
target,
abi.encodeWithSignature("testMultipleReturn(uint256)", num),
Expand All @@ -95,28 +117,41 @@ contract Twin is Initializable, Bridged, BridgedTwin {
);
emit SucceededMultipleReturn(num, num2, num3);
} else {
bytes4 sig = bytes4(res[:4]);
bytes4(res[:4]);
bytes memory err = bytes(res[4:]);
emit Failed(abi.decode(err, (string)));
}
}
}

contract Target {
uint private _num = 1;

event TestNoReturn(uint num);
event TestSum(uint num);

function test(uint num_) external pure returns (uint) {
require(num_ < 1000, "Too large");
return num_ + 1;
}

function testSum(uint num_) external returns (uint) {
_num += num_;
emit TestSum(_num);
return _num;
}

function test(uint num) external pure returns (uint) {
require(num < 1000, "Too large");
return num + 1;
function num() external view returns (uint) {
return _num;
}

function testNoReturn(uint num) external {
emit TestNoReturn(num + 1);
function testNoReturn(uint num_) external {
emit TestNoReturn(num_ + 1);
}

function testMultipleReturn(
uint num
uint num_
) external pure returns (uint, uint, uint) {
return (num + 1, num + 2, num + 3);
return (num_ + 1, num_ + 2, num_ + 3);
}
}
22 changes: 12 additions & 10 deletions products/bridge/smart-contracts/test/erc20bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ describe("ERC20Bridge", function () {
[await relayer1.getAddress(), chainId2]
);

expect(
await relayer1.deployTwin(salt, ERC20Bridge__factory.bytecode, initCall1)
await expect(
relayer1.deployTwin(salt, ERC20Bridge__factory.bytecode, initCall1)
)
.to.emit(relayer1, "Deployed")
.to.emit(relayer1, "TwinDeployment")
.withArgs(bridgeAddress);

const bridge1 = await ethers.getContractAt("ERC20Bridge", bridgeAddress);
Expand All @@ -66,10 +66,10 @@ describe("ERC20Bridge", function () {
[await relayer2.getAddress(), chainId1]
);

expect(
await relayer2.deployTwin(salt, ERC20Bridge__factory.bytecode, initCall2)
await expect(
relayer2.deployTwin(salt, ERC20Bridge__factory.bytecode, initCall2)
)
.to.emit(relayer2, "Deployed")
.to.emit(relayer2, "TwinDeployment")
.withArgs(bridgeAddress);
const bridge2 = await ethers.getContractAt("ERC20Bridge", bridgeAddress);

Expand Down Expand Up @@ -131,17 +131,18 @@ describe("ERC20Bridge", function () {
.connect(tester1)
.approve(await bridge1.getAddress(), value);
await tx.wait();
expect(tx)
await expect(tx)
.to.emit(token1, "Approval")
.withArgs(tester1.address, await bridge1.getAddress(), value);

tx = await bridge1
.connect(tester1)
.bridge(await token2.getAddress(), tester1.address, value);
await tx.wait();
expect(tx)
await expect(tx)
.to.emit(relayer1, "Relayed")
.withArgs(
targetChainId,
await bridge1.getAddress(),
await token2.getAddress(),
token2.interface.encodeFunctionData("mint", [tester1.address, value]),
Expand Down Expand Up @@ -235,17 +236,18 @@ describe("ERC20Bridge", function () {
.connect(tester2)
.approve(await bridge2.getAddress(), value);
await tx.wait();
expect(tx)
await expect(tx)
.to.emit(token2, "Approval")
.withArgs(tester2.address, await bridge2.getAddress(), value);

tx = await bridge2
.connect(tester2)
.exit(await token1.getAddress(), tester2.address, value);
await tx.wait();
expect(tx)
await expect(tx)
.to.emit(relayer2, "Relayed")
.withArgs(
targetChainId,
await bridge2.getAddress(),
await token1.getAddress(),
token1.interface.encodeFunctionData("transfer", [
Expand Down
118 changes: 113 additions & 5 deletions products/bridge/smart-contracts/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ describe("Bridge", function () {
[await relayer1.getAddress(), chainId2]
);

expect(await relayer1.deployTwin(salt, Twin__factory.bytecode, initCall1))
.to.emit(relayer1, "Deployed")
await expect(
await relayer1.deployTwin(salt, Twin__factory.bytecode, initCall1)
)
.to.emit(relayer1, "TwinDeployment")
.withArgs(twinAddress);

const twin1 = await ethers.getContractAt("Twin", twinAddress);
Expand All @@ -54,8 +56,10 @@ describe("Bridge", function () {
[await relayer2.getAddress(), chainId1]
);

expect(await relayer2.deployTwin(salt, Twin__factory.bytecode, initCall2))
.to.emit(relayer2, "Deployed")
await expect(
await relayer2.deployTwin(salt, Twin__factory.bytecode, initCall2)
)
.to.emit(relayer2, "TwinDeployment")
.withArgs(twinAddress);

const twin2 = await ethers.getContractAt("Twin", twinAddress);
Expand Down Expand Up @@ -437,7 +441,111 @@ describe("Bridge", function () {
]);
});

// TODO: add test for simultaneous remote calls requested by the same contract
it("should handle multiple remote calls requested by the same contract", async function () {
const {
collector,
twin1,
target2,
relayer1,
relayer2,
validators1,
validators2,
chainId1,
chainId2,
} = await setup(); // instead of loadFixture(setup);
const num = 124;
const num2 = 130;
const sourceChainId = chainId1;
const targetChainId = chainId2;
const readonly = false;

switchNetwork(1);

const tx = await twin1
.connect(validators1[0])
.startSum(await target2.getAddress(), num, readonly);
await tx.wait();
await expect(tx)
.to.emit(relayer1, "Relayed")
.withArgs(
targetChainId,
await twin1.getAddress(),
await target2.getAddress(),
target2.interface.encodeFunctionData("testSum", [num]),
readonly,
twin1.interface.getFunction("finishSum").selector,
anyValue
);

const { dispatchTxn } = await dispatchMessage(
1,
2,
sourceChainId,
targetChainId,
validators1,
relayer1,
validators2,
relayer2,
validators1,
collector,
true,
readonly,
ethers.AbiCoder.defaultAbiCoder().encode(["uint256"], [num + 1])
);

const filter = twin1.filters.Succeeded;
const logs = await twin1.queryFilter(filter);
expect(logs).is.not.empty;
expect(logs[0].args).to.deep.equal([BigInt(num + 1)]);

expect(await target2.num()).to.equal(num + 1);
await expect(dispatchTxn)
.to.emit(target2, "TestSum")
.withArgs(num + 1);

switchNetwork(1);

const tx2 = await twin1
.connect(validators1[0])
.startSum(await target2.getAddress(), num2, readonly);
await tx2.wait();
await expect(tx2)
.to.emit(relayer1, "Relayed")
.withArgs(
targetChainId,
await twin1.getAddress(),
await target2.getAddress(),
target2.interface.encodeFunctionData("testSum", [num2]),
readonly,
twin1.interface.getFunction("finishSum").selector,
anyValue
);

const { dispatchTxn: dispatchTxn2 } = await dispatchMessage(
1,
2,
sourceChainId,
targetChainId,
validators1,
relayer1,
validators2,
relayer2,
validators1,
collector,
true,
readonly,
ethers.AbiCoder.defaultAbiCoder().encode(["uint256"], [num2 + num + 1])
);

const logs2 = await twin1.queryFilter(twin1.filters.Succeeded);
expect(logs2).is.not.empty;
expect(logs2[1].args).to.deep.equal([BigInt(num2 + num + 1)]);

expect(await target2.num()).to.equal(num2 + num + 1);
await expect(dispatchTxn2)
.to.emit(target2, "TestSum")
.withArgs(num2 + num + 1);
});

it("should fail to replay the same remote call, only first one going through", async function () {
const {
Expand Down
Loading

0 comments on commit 12d3423

Please sign in to comment.