-
Notifications
You must be signed in to change notification settings - Fork 2
Impl unit tests #16
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
Impl unit tests #16
Changes from 10 commits
c72f295
f7a8a05
e60c231
b24e48a
19ee209
b9c33ad
ec5116b
48fda91
7b019d8
d90e8de
13d6bfc
f7da2e0
a6fd5fe
51a84ae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,7 +41,6 @@ import {ILightClient} from "@hyperledger-labs/yui-ibc-solidity/contracts/core/02 | |
| contract DeployAll is Script, Config { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I split the function because solhint complained about function-max-lines (I wonder why it didn't complain before? I don't know why). |
||
| // === Deployment artifacts (written back to deployments.toml) === | ||
| IBCHandler public ibcHandler; | ||
|
|
||
| MockCrossContract public mockApp; | ||
| CrossSimpleModule public crossSimpleModule; | ||
| MockClient public mockClient; | ||
|
|
@@ -92,65 +91,96 @@ contract DeployAll is Script, Config { | |
| console2.log(" Initialized. port=%s, clientType=%s", portCross, mockClientType); | ||
| } | ||
|
|
||
| // ---------- entry ---------- | ||
| function run() external { | ||
| // 1) Load config with write-back enabled (stores results after deployment) | ||
| _loadConfig( | ||
| "./deployments.toml", | ||
| /*writeBack=*/ | ||
| true | ||
| ); | ||
| function _readConfig() | ||
| internal | ||
| returns ( | ||
| string memory mnemonic, | ||
| uint32 mnemonicIndex, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType | ||
| ) | ||
| { | ||
| string memory m = config.get("mnemonic").toString(); | ||
| uint256 idxU256 = config.get("mnemonic_index").toUint256(); | ||
| require(idxU256 < 2 ** 32, "mnemonic_index too large"); | ||
| uint32 idx = uint32(idxU256); | ||
| bool dbg = config.get("debug_mode").toBool(); | ||
| string memory port = config.get("port_cross").toString(); | ||
| string memory cli = config.get("mock_client_type").toString(); | ||
| return (m, idx, dbg, port, cli); | ||
| } | ||
|
|
||
| uint256 chainId = block.chainid; | ||
| function _logConfig( | ||
| uint256 chainId, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType, | ||
| uint32 mnemonicIndex | ||
| ) internal { | ||
| console2.log("Deploying to chain:", chainId); | ||
|
|
||
| // 2) Read configuration values (resolved for the current chain) | ||
| // - Required: | ||
| // string: mnemonic | ||
| // uint: mnemonic_index | ||
| // bool: debug_mode | ||
| // string: port_cross | ||
| // string: mock_client_type | ||
| string memory mnemonic = config.get("mnemonic").toString(); | ||
| uint256 mnemonicIndexU256 = config.get("mnemonic_index").toUint256(); | ||
| // solhint-disable-next-line gas-strict-inequalities | ||
| require(mnemonicIndexU256 <= type(uint32).max, "mnemonic_index too large"); | ||
| uint32 mnemonicIndex = uint32(mnemonicIndexU256); | ||
|
|
||
| bool debugMode = config.get("debug_mode").toBool(); | ||
| string memory portCross = config.get("port_cross").toString(); | ||
| string memory mockClientType = config.get("mock_client_type").toString(); | ||
|
|
||
| console2.log("Config:"); | ||
| console2.log(" debug_mode :", debugMode); | ||
| console2.log(" port_cross :", portCross); | ||
| console2.log(" mock_client_type:", mockClientType); | ||
| console2.log(" mnemonic_index :", mnemonicIndex); | ||
| } | ||
|
|
||
| // 3) Derive deployer private key from mnemonic + index (Foundry cheatcode) | ||
| uint256 deployerPk = vm.deriveKey(mnemonic, mnemonicIndex); | ||
| address deployer = vm.addr(deployerPk); | ||
| console2.log("Deployer:", deployer); | ||
| function _deriveDeployer(string memory mnemonic, uint32 mnemonicIndex) | ||
| internal | ||
| returns (uint256 deployerPk, address deployer) | ||
| { | ||
| uint256 pk = vm.deriveKey(mnemonic, mnemonicIndex); | ||
| address addr = vm.addr(pk); | ||
| console2.log("Deployer:", addr); | ||
| return (pk, addr); | ||
| } | ||
|
|
||
| // 4) Deploy + Initialize (single broadcast session) | ||
| function _broadcastDeployAndInit( | ||
| uint256 deployerPk, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType | ||
| ) internal { | ||
| vm.startBroadcast(deployerPk); | ||
|
|
||
| ibcHandler = _deployCore(); | ||
| (mockApp, crossSimpleModule, mockClient) = _deployApp(ibcHandler, debugMode); | ||
| _initialize(ibcHandler, crossSimpleModule, portCross, mockClientType, mockClient); | ||
|
|
||
| vm.stopBroadcast(); | ||
| } | ||
|
|
||
| // 5) Write back: save addresses & metadata to deployments.toml | ||
| // (addresses go under <chain>.address.*, meta under <chain>.meta.*) | ||
| function _writeBack(address deployer) internal { | ||
| // save addresses & metadata to deployments.toml | ||
| // (addresses go under <chain>.address.*, meta under <chain>.meta.*) | ||
| config.set("ibc_handler", address(ibcHandler)); | ||
| config.set("mock_cross_contract", address(mockApp)); | ||
| config.set("cross_simple_module", address(crossSimpleModule)); | ||
| config.set("mock_client", address(mockClient)); | ||
|
|
||
| // Meta | ||
| config.set("deployer", deployer); | ||
|
|
||
| console2.log("\nDeployment complete! Addresses saved to deployments.toml"); | ||
| } | ||
|
|
||
| // ---------- entry ---------- | ||
| function run() external { | ||
| _loadConfig("./deployments.toml", true); | ||
|
|
||
| uint256 chainId = block.chainid; | ||
| ( | ||
| string memory mnemonic, | ||
| uint32 mnemonicIndex, | ||
| bool debugMode, | ||
| string memory portCross, | ||
| string memory mockClientType | ||
| ) = _readConfig(); | ||
|
|
||
| _logConfig(chainId, debugMode, portCross, mockClientType, mnemonicIndex); | ||
|
|
||
| (uint256 deployerPk, address deployer) = _deriveDeployer(mnemonic, mnemonicIndex); | ||
|
|
||
| _broadcastDeployAndInit(deployerPk, debugMode, portCross, mockClientType); | ||
|
|
||
| _writeBack(deployer); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // solhint-disable one-contract-per-file, func-name-mixedcase | ||
| pragma solidity ^0.8.20; | ||
|
|
||
| import "forge-std/src/Test.sol"; | ||
|
|
||
| import "../src/core/CrossModule.sol"; | ||
| import { | ||
| IIBCModule, | ||
| IIBCModuleInitializer | ||
| } from "@hyperledger-labs/yui-ibc-solidity/contracts/core/26-router/IIBCModule.sol"; | ||
| import {IIBCHandler} from "@hyperledger-labs/yui-ibc-solidity/contracts/core/25-handler/IIBCHandler.sol"; | ||
| import {Packet} from "@hyperledger-labs/yui-ibc-solidity/contracts/core/04-channel/IIBCChannel.sol"; | ||
|
|
||
| import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol"; | ||
|
|
||
| contract DummyHandler {} | ||
|
|
||
| contract TestableCrossModule is CrossModule { | ||
| uint256 public recvCount; | ||
| uint256 public ackCount; | ||
| uint256 public timeoutCount; | ||
| bytes public lastAckArg; | ||
|
|
||
| constructor(IIBCHandler h) CrossModule(h) {} | ||
|
|
||
| function handlePacket( | ||
| Packet memory /*packet*/ | ||
| ) | ||
| internal | ||
| virtual | ||
| override | ||
| returns (bytes memory) | ||
| { | ||
| ++recvCount; | ||
| return bytes("ack-ok"); | ||
| } | ||
|
|
||
| function handleAcknowledgement( | ||
| Packet memory, | ||
| /*packet*/ | ||
| bytes memory acknowledgement | ||
| ) | ||
| internal | ||
| virtual | ||
| override | ||
| { | ||
| ++ackCount; | ||
| lastAckArg = acknowledgement; | ||
| } | ||
|
|
||
| function handleTimeout( | ||
| Packet calldata /*packet*/ | ||
| ) | ||
| internal | ||
| virtual | ||
| override | ||
| { | ||
| ++timeoutCount; | ||
| } | ||
| } | ||
|
|
||
| contract CrossModuleTest is Test { | ||
| DummyHandler private handler; | ||
| TestableCrossModule private mod; | ||
| Packet internal _emptyPacket; | ||
|
|
||
| function setUp() public { | ||
| handler = new DummyHandler(); | ||
| mod = new TestableCrossModule(IIBCHandler(address(handler))); | ||
| } | ||
|
|
||
| function test_Constructor_GrantsIbcRoleToHandler() public { | ||
| assertTrue(mod.hasRole(mod.IBC_ROLE(), address(handler))); | ||
| } | ||
|
|
||
| function test_SupportsInterface_IIBC_IAccessControl_And_Unsupported() public view { | ||
| assertTrue(mod.supportsInterface(type(IIBCModule).interfaceId)); | ||
| assertTrue(mod.supportsInterface(type(IIBCModuleInitializer).interfaceId)); | ||
| assertTrue(mod.supportsInterface(type(IAccessControl).interfaceId)); | ||
| assertFalse(mod.supportsInterface(0xDEADBEEF)); | ||
| } | ||
|
|
||
| function test_onRecvPacket_Reverts_WithoutIbcRole() public { | ||
| vm.expectRevert(); | ||
| mod.onRecvPacket(_emptyPacket, address(0)); | ||
| } | ||
|
|
||
| function test_onRecvPacket_CallsHandlerAndReturnsAck_WhenCallerHasRole() public { | ||
| vm.prank(address(handler)); | ||
| bytes memory ack = mod.onRecvPacket(_emptyPacket, address(0)); | ||
| assertEq(ack, bytes("ack-ok")); | ||
| assertEq(mod.recvCount(), 1); | ||
| } | ||
|
|
||
| function test_onAcknowledgementPacket_Reverts_WithoutIbcRole() public { | ||
| vm.expectRevert(); | ||
| mod.onAcknowledgementPacket(_emptyPacket, bytes("ack"), address(0)); | ||
| } | ||
|
|
||
| function test_onAcknowledgementPacket_CallsHandler_WhenCallerHasRole() public { | ||
| vm.prank(address(handler)); | ||
| mod.onAcknowledgementPacket(_emptyPacket, bytes("ack123"), address(0)); | ||
| assertEq(mod.ackCount(), 1); | ||
| assertEq(mod.lastAckArg(), bytes("ack123")); | ||
| } | ||
|
|
||
| function test_onTimeoutPacket_Reverts_WithoutIbcRole() public { | ||
| vm.expectRevert(); | ||
| mod.onTimeoutPacket(_emptyPacket, address(0)); | ||
| } | ||
|
|
||
| function test_onTimeoutPacket_CallsHandler_WhenCallerHasRole() public { | ||
| vm.prank(address(handler)); | ||
| mod.onTimeoutPacket(_emptyPacket, address(0)); | ||
| assertEq(mod.timeoutCount(), 1); | ||
| } | ||
|
|
||
| function test_onChanOpenInit_Reverts_WithoutIbcRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenInit memory m; | ||
| m.version = "v1"; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenInit(m); | ||
| } | ||
|
|
||
| function test_onChanOpenInit_ReturnsSelfAndVersion_WhenCallerHasRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenInit memory m; | ||
| m.version = "v1"; | ||
| vm.prank(address(handler)); | ||
| (address moduleAddr, string memory version) = mod.onChanOpenInit(m); | ||
| assertEq(moduleAddr, address(mod)); | ||
| assertEq(version, "v1"); | ||
| } | ||
|
|
||
| function test_onChanOpenTry_Reverts_WithoutIbcRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenTry memory m; | ||
| m.counterpartyVersion = "cp-v1"; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenTry(m); | ||
| } | ||
|
|
||
| function test_onChanOpenTry_ReturnsSelfAndCounterpartyVersion_WhenCallerHasRole() public { | ||
| IIBCModuleInitializer.MsgOnChanOpenTry memory m; | ||
| m.counterpartyVersion = "cp-v1"; | ||
| vm.prank(address(handler)); | ||
| (address moduleAddr, string memory version) = mod.onChanOpenTry(m); | ||
| assertEq(moduleAddr, address(mod)); | ||
| assertEq(version, "cp-v1"); | ||
| } | ||
|
|
||
| function test_onChanOpenAck_Reverts_WithoutIbcRole() public { | ||
| IIBCModule.MsgOnChanOpenAck memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenAck(m); | ||
| } | ||
|
|
||
| function test_onChanOpenAck_Succeeds_WhenCallerHasRole() public { | ||
| IIBCModule.MsgOnChanOpenAck memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanOpenAck(m); // no revert | ||
| } | ||
|
|
||
| function test_onChanOpenConfirm_Reverts_WithoutIbcRole() public { | ||
| IIBCModule.MsgOnChanOpenConfirm memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanOpenConfirm(m); | ||
| } | ||
|
|
||
| function test_onChanOpenConfirm_Succeeds_WhenCallerHasRole() public { | ||
| IIBCModule.MsgOnChanOpenConfirm memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanOpenConfirm(m); // no revert | ||
| } | ||
|
|
||
| function test_onChanCloseInit_Reverts_WithoutIbcRole() public { | ||
| IIBCModule.MsgOnChanCloseInit memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanCloseInit(m); | ||
| } | ||
|
|
||
| function test_onChanCloseInit_Succeeds_WhenCallerHasRole() public { | ||
| IIBCModule.MsgOnChanCloseInit memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanCloseInit(m); // no revert | ||
| } | ||
|
|
||
| function test_onChanCloseConfirm_Reverts_WithoutIbcRole() public { | ||
| IIBCModule.MsgOnChanCloseConfirm memory m; | ||
| vm.expectRevert(); | ||
| mod.onChanCloseConfirm(m); | ||
| } | ||
|
|
||
| function test_onChanCloseConfirm_Succeeds_WhenCallerHasRole() public { | ||
|
||
| IIBCModule.MsgOnChanCloseConfirm memory m; | ||
| vm.prank(address(handler)); | ||
| mod.onChanCloseConfirm(m); // no revert | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exclude because coverage measurement is not required