Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SMR 2237 Fuzz testing #88

Merged
merged 7 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) && user != address(this));

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) && user != address(this));
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
Loading