Skip to content

Commit

Permalink
Add fuzz testing
Browse files Browse the repository at this point in the history
  • Loading branch information
wcgcyx committed Feb 7, 2024
1 parent c893754 commit a63e6cc
Show file tree
Hide file tree
Showing 8 changed files with 1,220 additions and 0 deletions.
94 changes: 94 additions & 0 deletions test/fuzz/child/ChildAxelarBridgeAdaptor.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity 0.8.19;

import {Test} from "forge-std/Test.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";
import {
IChildAxelarBridgeAdaptorErrors,
IChildAxelarBridgeAdaptorEvents,
IChildAxelarBridgeAdaptor
} from "../../../src/interfaces/child/IChildAxelarBridgeAdaptor.sol";
import {ChildAxelarBridgeAdaptor} from "../../../src/child/ChildAxelarBridgeAdaptor.sol";
import {MockChildERC20Bridge} from "../../mocks/child/MockChildERC20Bridge.sol";
import {MockChildAxelarGateway} from "../../mocks/child/MockChildAxelarGateway.sol";
import {MockChildAxelarGasService} from "../../mocks/child/MockChildAxelarGasService.sol";

contract ChildAxelarBridgeAdaptorTest is Test, IChildAxelarBridgeAdaptorErrors, IChildAxelarBridgeAdaptorEvents {
string public constant ROOT_CHAIN_NAME = "root";
string public ROOT_BRIDGE_ADAPTOR = Strings.toHexString(address(4));

ChildAxelarBridgeAdaptor public axelarAdaptor;
MockChildERC20Bridge public mockChildERC20Bridge;
MockChildAxelarGateway public mockChildAxelarGateway;
MockChildAxelarGasService public mockChildAxelarGasService;

function setUp() public {
IChildAxelarBridgeAdaptor.InitializationRoles memory roles = IChildAxelarBridgeAdaptor.InitializationRoles({
defaultAdmin: address(this),
bridgeManager: address(this),
gasServiceManager: address(this),
targetManager: address(this)
});

mockChildERC20Bridge = new MockChildERC20Bridge();
mockChildAxelarGateway = new MockChildAxelarGateway();
mockChildAxelarGasService = new MockChildAxelarGasService();

axelarAdaptor = new ChildAxelarBridgeAdaptor(address(mockChildAxelarGateway), address(this));
axelarAdaptor.initialize(
roles,
address(mockChildERC20Bridge),
ROOT_CHAIN_NAME,
ROOT_BRIDGE_ADAPTOR,
address(mockChildAxelarGasService)
);
}

function testFuzz_SendMessage(uint256 callValue, bytes calldata payload, address refundRecipient) public {
vm.assume(callValue > 0 && callValue < type(uint256).max);

vm.startPrank(address(mockChildERC20Bridge));
vm.deal(address(mockChildERC20Bridge), callValue);

// Send message called with insufficient balance should revert
vm.expectRevert();
axelarAdaptor.sendMessage{value: callValue + 1}(payload, refundRecipient);

// Send message correctly should call gas service and gateway with expected data
vm.expectCall(
address(mockChildAxelarGasService),
callValue,
abi.encodeWithSelector(
mockChildAxelarGasService.payNativeGasForContractCall.selector,
address(axelarAdaptor),
ROOT_CHAIN_NAME,
axelarAdaptor.rootBridgeAdaptor(),
payload,
refundRecipient
)
);
vm.expectCall(
address(mockChildAxelarGateway),
abi.encodeWithSelector(
mockChildAxelarGateway.callContract.selector,
ROOT_CHAIN_NAME,
axelarAdaptor.rootBridgeAdaptor(),
payload
)
);
axelarAdaptor.sendMessage{value: callValue}(payload, refundRecipient);

vm.stopPrank();
}

function testFuzz_Execute(bytes32 commandId, bytes calldata payload) public {
// Execute should emit event and call bridge.
vm.expectEmit();
emit AdaptorExecute(ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, payload);
vm.expectCall(
address(mockChildERC20Bridge),
abi.encodeWithSelector(mockChildERC20Bridge.onMessageReceive.selector, payload)
);
axelarAdaptor.execute(commandId, ROOT_CHAIN_NAME, ROOT_BRIDGE_ADAPTOR, payload);
}
}
55 changes: 55 additions & 0 deletions test/fuzz/child/ChildERC20.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-License-Identifier: Apache 2.0
pragma solidity 0.8.19;

import {Test} from "forge-std/Test.sol";
import {ChildERC20} from "../../../src/child/ChildERC20.sol";

contract ChildERC20Test is Test {
ChildERC20 public childToken;

address constant DEFAULT_ROOT_ADDRESS = address(111);
string constant DEFAULT_NAME = "Test ERC20";
string constant DEFAULT_SYMBOL = "TEST";
uint8 constant DEFAULT_DECIMALS = 18;

function setUp() public {
childToken = new ChildERC20();
childToken.initialize(DEFAULT_ROOT_ADDRESS, DEFAULT_NAME, DEFAULT_SYMBOL, DEFAULT_DECIMALS);
}

function testFuzz_Mint(address user, uint256 amount) public {
vm.assume(user != address(0));

assertEq(childToken.balanceOf(user), 0, "User should not have balance before mint");

// Unauthorised mint should revert
vm.prank(user);
vm.expectRevert("ChildERC20: Only bridge can call");
childToken.mint(user, amount);

childToken.mint(user, amount);
assertEq(childToken.balanceOf(user), amount, "User should have given amount of balance after mint");
}

function testFuzz_Burn(address user, uint256 balance, uint256 burnAmt) public {
vm.assume(user != address(0));
vm.assume(balance < type(uint256).max);
vm.assume(burnAmt < balance);

childToken.mint(user, balance);
assertEq(childToken.balanceOf(user), balance, "User should have given amount of balance before burn");

// Unauthorised burn should revert
vm.prank(user);
vm.expectRevert("ChildERC20: Only bridge can call");
childToken.burn(user, burnAmt);

// Over burn should revert
vm.expectRevert("ERC20: burn amount exceeds balance");
childToken.burn(user, balance + 1);

// Burn should decrease balance
childToken.burn(user, burnAmt);
assertEq(childToken.balanceOf(user), balance - burnAmt, "User should have balance - burnAmt after burn");
}
}
Loading

0 comments on commit a63e6cc

Please sign in to comment.