diff --git a/remappings.txt b/remappings.txt index 4870f8f5..9b4fbfd9 100644 --- a/remappings.txt +++ b/remappings.txt @@ -8,4 +8,4 @@ hardhat/=node_modules/hardhat/ @prb/test/=lib/prb-test/src/ @prb/math/=lib/prb-math/ solady/=lib/solady/src/ -foundry-deployment-kit/=lib/foundry-deployment-kit/script/ \ No newline at end of file +foundry-deployment-kit/=lib/foundry-deployment-kit/script/ diff --git a/script/20231218-maptoken/20231218-maptoken-mainchain.s.sol b/script/20231218-maptoken/20231218-maptoken-mainchain.s.sol new file mode 100644 index 00000000..e7a72225 --- /dev/null +++ b/script/20231218-maptoken/20231218-maptoken-mainchain.s.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { console2 } from "forge-std/console2.sol"; +import { StdStyle } from "forge-std/StdStyle.sol"; +import { BaseMigration } from "foundry-deployment-kit/BaseMigration.s.sol"; +import { RoninBridgeManager } from "@ronin/contracts/ronin/gateway/RoninBridgeManager.sol"; +import { IMainchainGatewayV3 } from "@ronin/contracts/interfaces/IMainchainGatewayV3.sol"; +import { GlobalProposal } from "@ronin/contracts/libraries/GlobalProposal.sol"; +import { Token } from "@ronin/contracts/libraries/Token.sol"; +import { Contract } from "../utils/Contract.sol"; +import { BridgeMigration } from "../BridgeMigration.sol"; +import { Network } from "../utils/Network.sol"; +import { Contract } from "../utils/Contract.sol"; +import { IGeneralConfigExtended } from "../IGeneralConfigExtended.sol"; + +contract Migration__20231215_MapTokenMainchain is BridgeMigration { + RoninBridgeManager internal _roninBridgeManager; + address constant _aggRoninToken = address(0x294311a8C37F0744F99EB152c419D4D3D6FEC1C7); + address constant _aggMainchainToken = address(0xFB0489e9753B045DdB35e39c6B0Cc02EC6b99AC5); + address internal _mainchainGatewayV3; + + // The decimal of AGG token is 18 + uint256 constant _highTierThreshold = 200_000_000 ether; + uint256 constant _lockedThreshold = 800_000_000 ether; + // The MAX_PERCENTAGE is 1_000_000 + uint256 constant _unlockFeePercentages = 10; + uint256 constant _dailyWithdrawalLimit = 500_000_000 ether; + + function setUp() public override { + super.setUp(); + + _roninBridgeManager = RoninBridgeManager(_config.getAddressFromCurrentNetwork(Contract.RoninBridgeManager.key())); + _mainchainGatewayV3 = _config.getAddress( + _config.getCompanionNetwork(_config.getNetworkByChainId(block.chainid)).key(), Contract.MainchainGatewayV3.key() + ); + } + + function run() public { + address[] memory mainchainTokens = new address[](1); + mainchainTokens[0] = _aggMainchainToken; + address[] memory roninTokens = new address[](1); + roninTokens[0] = _aggRoninToken; + Token.Standard[] memory standards = new Token.Standard[](1); + standards[0] = Token.Standard.ERC20; + uint256[][4] memory thresholds; + // highTierThreshold + thresholds[0] = new uint256[](1); + thresholds[0][0] = _highTierThreshold; + // lockedThreshold + thresholds[1] = new uint256[](1); + thresholds[1][0] = _lockedThreshold; + // unlockFeePercentages + thresholds[2] = new uint256[](1); + thresholds[2][0] = _unlockFeePercentages; + // dailyWithdrawalLimit + thresholds[3] = new uint256[](1); + thresholds[3][0] = _dailyWithdrawalLimit; + + // function mapTokensAndThresholds( + // address[] calldata _mainchainTokens, + // address[] calldata _roninTokens, + // Token.Standard[] calldata _standards, + // uint256[][4] calldata _thresholds + // ) + + bytes memory innerData = + abi.encodeCall(IMainchainGatewayV3.mapTokensAndThresholds, (mainchainTokens, roninTokens, standards, thresholds)); + bytes memory proxyData = abi.encodeWithSignature("functionDelegateCall(bytes)", innerData); + + uint256 expiredTime = block.timestamp + 10 days; + address[] memory targets = new address[](1); + targets[0] = _mainchainGatewayV3; + uint256[] memory values = new uint256[](1); + values[0] = 0; + bytes[] memory calldatas = new bytes[](1); + calldatas[0] = proxyData; + uint256[] memory gasAmounts = new uint256[](1); + gasAmounts[0] = 1_000_000; + + _verifyMainchainProposalGasAmount(targets, values, calldatas, gasAmounts); + + uint256 chainId = _config.getCompanionNetwork(_config.getNetworkByChainId(block.chainid)).chainId(); + + vm.broadcast(sender()); + _roninBridgeManager.propose(chainId, expiredTime, targets, values, calldatas, gasAmounts); + } +} diff --git a/script/20231218-maptoken/20231218-maptoken-roninchain.s.sol b/script/20231218-maptoken/20231218-maptoken-roninchain.s.sol new file mode 100644 index 00000000..5621946c --- /dev/null +++ b/script/20231218-maptoken/20231218-maptoken-roninchain.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { console2 } from "forge-std/console2.sol"; +import { StdStyle } from "forge-std/StdStyle.sol"; +import { BaseMigration } from "foundry-deployment-kit/BaseMigration.s.sol"; +import { RoninBridgeManager } from "@ronin/contracts/ronin/gateway/RoninBridgeManager.sol"; +import { IRoninGatewayV3 } from "@ronin/contracts/interfaces/IRoninGatewayV3.sol"; +import { Token } from "@ronin/contracts/libraries/Token.sol"; +import { Contract } from "../utils/Contract.sol"; +import { BridgeMigration } from "../BridgeMigration.sol"; +import { Network } from "../utils/Network.sol"; +import { Contract } from "../utils/Contract.sol"; +import { IGeneralConfigExtended } from "../IGeneralConfigExtended.sol"; + +contract Migration__20231215_MapTokenRoninchain is BridgeMigration { + RoninBridgeManager internal _roninBridgeManager; + address constant _aggRoninToken = address(0x294311a8C37F0744F99EB152c419D4D3D6FEC1C7); + address constant _aggMainchainToken = address(0xFB0489e9753B045DdB35e39c6B0Cc02EC6b99AC5); + address internal _roninGatewayV3; + + function setUp() public override { + super.setUp(); + _roninBridgeManager = RoninBridgeManager(_config.getAddressFromCurrentNetwork(Contract.RoninBridgeManager.key())); + _roninGatewayV3 = _config.getAddressFromCurrentNetwork(Contract.RoninGatewayV3.key()); + } + + function run() public { + address[] memory roninTokens = new address[](1); + roninTokens[0] = _aggRoninToken; + address[] memory mainchainTokens = new address[](1); + mainchainTokens[0] = _aggMainchainToken; + uint256[] memory chainIds = new uint256[](1); + chainIds[0] = _config.getCompanionNetwork(_config.getNetworkByChainId(block.chainid)).chainId(); + Token.Standard[] memory standards = new Token.Standard[](1); + standards[0] = Token.Standard.ERC20; + + // function mapTokens( + // address[] calldata _roninTokens, + // address[] calldata _mainchainTokens, + // uint256[] calldata chainIds, + // Token.Standard[] calldata _standards + // ) + bytes memory innerData = + abi.encodeCall(IRoninGatewayV3.mapTokens, (roninTokens, mainchainTokens, chainIds, standards)); + bytes memory proxyData = abi.encodeWithSignature("functionDelegateCall(bytes)", innerData); + + uint256 expiredTime = block.timestamp + 10 days; + address[] memory targets = new address[](1); + targets[0] = _roninGatewayV3; + uint256[] memory values = new uint256[](1); + values[0] = 0; + bytes[] memory calldatas = new bytes[](1); + calldatas[0] = proxyData; + uint256[] memory gasAmounts = new uint256[](1); + gasAmounts[0] = 1_000_000; + + _verifyRoninProposalGasAmount(targets, values, calldatas, gasAmounts); + + vm.broadcast(sender()); + _roninBridgeManager.propose(block.chainid, expiredTime, targets, values, calldatas, gasAmounts); + } +} diff --git a/script/BridgeMigration.sol b/script/BridgeMigration.sol new file mode 100644 index 00000000..a98deeb7 --- /dev/null +++ b/script/BridgeMigration.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { console2 } from "forge-std/console2.sol"; +import { BaseMigration } from "foundry-deployment-kit/BaseMigration.s.sol"; +import { GeneralConfigExtended } from "./GeneralConfigExtended.sol"; +import { RoninBridgeManager } from "@ronin/contracts/ronin/gateway/RoninBridgeManager.sol"; +import { ErrorHandler } from "@ronin/contracts/libraries/ErrorHandler.sol"; +import { IGeneralConfigExtended } from "./IGeneralConfigExtended.sol"; +import { Network } from "./utils/Network.sol"; +import { Contract } from "./utils/Contract.sol"; +import { DefaultNetwork } from "foundry-deployment-kit/utils/DefaultNetwork.sol"; + +contract BridgeMigration is BaseMigration { + using ErrorHandler for bool; + + error ErrProposalOutOfGas(bytes4 sig, uint256 expectedGas); + + IGeneralConfigExtended internal constant _config = IGeneralConfigExtended(address(CONFIG)); + + function _configByteCode() internal virtual override returns (bytes memory) { + return abi.encodePacked(type(GeneralConfigExtended).creationCode); + } + + function _sharedArguments() internal virtual override returns (bytes memory rawArgs) { + return ""; + } + + function _verifyRoninProposalGasAmount( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + uint256[] memory gasAmounts + ) internal { + address roninBridgeManager = _config.getAddressFromCurrentNetwork(Contract.RoninBridgeManager.key()); + uint256 snapshotId = vm.snapshot(); + vm.startPrank(address(roninBridgeManager)); + _verifyProposalGasAmount(roninBridgeManager, targets, values, calldatas, gasAmounts); + vm.stopPrank(); + vm.revertTo(snapshotId); + } + + function _verifyMainchainProposalGasAmount( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + uint256[] memory gasAmounts + ) internal { + _config.createFork(Network.EthMainnet.key()); + _config.switchTo(Network.EthMainnet.key()); + + address mainchainBridgeManager = _config.getAddressFromCurrentNetwork(Contract.MainchainBridgeManager.key()); + uint256 snapshotId = vm.snapshot(); + + vm.startPrank(address(mainchainBridgeManager)); + _verifyProposalGasAmount(mainchainBridgeManager, targets, values, calldatas, gasAmounts); + vm.stopPrank(); + vm.revertTo(snapshotId); + + _config.switchTo(DefaultNetwork.RoninMainnet.key()); + } + + function _verifyProposalGasAmount( + address bridgeManager, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + uint256[] memory gasAmounts + ) private { + for (uint256 i; i < targets.length; i++) { + vm.deal(address(bridgeManager), values[i]); + uint256 gasUsed = gasleft(); + (bool success, bytes memory returnOrRevertData) = targets[i].call{ value: values[i] }(calldatas[i]); + gasUsed = gasUsed - gasleft(); + success.handleRevert(bytes4(calldatas[i]), returnOrRevertData); + + console2.log("Call", i, ": gasUsed", gasUsed); + if (gasUsed > gasAmounts[i]) { + revert ErrProposalOutOfGas(bytes4(calldatas[i]), gasUsed); + } + } + } +} diff --git a/script/GeneralConfigExtended.sol b/script/GeneralConfigExtended.sol new file mode 100644 index 00000000..1d2f5ccb --- /dev/null +++ b/script/GeneralConfigExtended.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { console2 as console } from "forge-std/console2.sol"; +import { TContract } from "foundry-deployment-kit/types/Types.sol"; +import { BaseGeneralConfig } from "foundry-deployment-kit/BaseGeneralConfig.sol"; +import { TNetwork } from "foundry-deployment-kit/types/Types.sol"; +import { DefaultNetwork } from "foundry-deployment-kit/utils/DefaultNetwork.sol"; +import { Network } from "./utils/Network.sol"; +import { Contract } from "./utils/Contract.sol"; + +contract GeneralConfigExtended is BaseGeneralConfig { + constructor() BaseGeneralConfig("", "deployments/") { } + + function _setUpNetworks() internal virtual override { + setNetworkInfo( + Network.Goerli.chainId(), + Network.Goerli.key(), + Network.Goerli.chainAlias(), + Network.Goerli.deploymentDir(), + Network.Goerli.envLabel(), + Network.Goerli.explorer() + ); + setNetworkInfo( + Network.EthMainnet.chainId(), + Network.EthMainnet.key(), + Network.EthMainnet.chainAlias(), + Network.EthMainnet.deploymentDir(), + Network.EthMainnet.envLabel(), + Network.EthMainnet.explorer() + ); + } + + function _setUpContracts() internal virtual override { + _mapContractname(Contract.BridgeReward); + _mapContractname(Contract.BridgeSlash); + _mapContractname(Contract.BridgeTracking); + _mapContractname(Contract.RoninBridgeManager); + _mapContractname(Contract.RoninGatewayV3); + _mapContractname(Contract.MainchainBridgeManager); + _mapContractname(Contract.MainchainGatewayV3); + } + + function _mapContractname(Contract contractEnum) internal { + _contractNameMap[contractEnum.key()] = contractEnum.name(); + } + + function getCompanionNetwork(TNetwork network) external pure returns (Network) { + if (network == DefaultNetwork.RoninTestnet.key()) return Network.Goerli; + if (network == DefaultNetwork.RoninMainnet.key()) return Network.EthMainnet; + revert("Network: Unknown companion network"); + } +} diff --git a/script/IGeneralConfigExtended.sol b/script/IGeneralConfigExtended.sol new file mode 100644 index 00000000..78a02582 --- /dev/null +++ b/script/IGeneralConfigExtended.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { IGeneralConfig } from "foundry-deployment-kit/interfaces/IGeneralConfig.sol"; +import { TNetwork } from "foundry-deployment-kit/types/Types.sol"; +import { Network } from "./utils/Network.sol"; + +interface IGeneralConfigExtended is IGeneralConfig { + /** + * @dev Returns the companion mainchain network of a roninchain network + * + * Input: roninchain network + * Output: companion mainchain network of roninchain + * + */ + function getCompanionNetwork(TNetwork network) external pure returns (Network); +}