diff --git a/contracts/Utils/ACMCommandsAggregator.sol b/contracts/Utils/ACMCommandsAggregator.sol new file mode 100644 index 00000000..a5de471d --- /dev/null +++ b/contracts/Utils/ACMCommandsAggregator.sol @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: BSD-3-Clause +pragma solidity 0.8.25; + +import { IAccessControlManagerV8 } from "../Governance/IAccessControlManagerV8.sol"; +import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol"; + +/** + * @title ACMCommandsAggregator + * @author Venus + * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go. + */ +contract ACMCommandsAggregator { + /* + * @notice Struct to store permission details + */ + struct Permission { + /* + * @notice Address of the contract + */ + address contractAddress; + /* + * @notice Function signature + */ + string functionSig; + /* + * @notice Address of the account + */ + address account; + } + + /** + * @notice Access control manager contract + */ + IAccessControlManagerV8 public immutable ACM; + + /* + * @notice 2D array to store grant permissions in batches + */ + Permission[][] public grantPermissions; + + /* + * @notice 2D array to store revoke permissions in batches + */ + Permission[][] public revokePermissions; + + /* + * @notice Event emitted when grant permissions are added + */ + event GrantPermissionsAdded(uint256 index); + + /* + * @notice Event emitted when revoke permissions are added + */ + event RevokePermissionsAdded(uint256 index); + + /* + * @notice Event emitted when grant permissions are executed + */ + event GrantPermissionsExecuted(uint256 index); + + /* + * @notice Event emitted when revoke permissions are executed + */ + event RevokePermissionsExecuted(uint256 index); + + /* + * @notice Error to be thrown when permissions are empty + */ + error EmptyPermissions(); + + /* + * @notice Constructor to set the access control manager + * @param _acm Address of the access control manager + */ + constructor(IAccessControlManagerV8 _acm) { + ensureNonzeroAddress(address(_acm)); + ACM = _acm; + } + + /* + * @notice Function to add grant permissions + * @param _permissions Array of permissions + * @custom:event Emits GrantPermissionsAdded event + */ + function addGrantPermissions(Permission[] memory _permissions) external { + if (_permissions.length == 0) { + revert EmptyPermissions(); + } + + uint256 index = grantPermissions.length; + grantPermissions.push(); + + for (uint256 i; i < _permissions.length; ++i) { + grantPermissions[index].push( + Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account) + ); + } + + emit GrantPermissionsAdded(index); + } + + /* + * @notice Function to add revoke permissions + * @param _permissions Array of permissions + * @custom:event Emits RevokePermissionsAdded event + */ + function addRevokePermissions(Permission[] memory _permissions) external { + if (_permissions.length == 0) { + revert EmptyPermissions(); + } + + uint256 index = revokePermissions.length; + revokePermissions.push(); + + for (uint256 i; i < _permissions.length; ++i) { + revokePermissions[index].push( + Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account) + ); + } + + emit RevokePermissionsAdded(index); + } + + /* + * @notice Function to execute grant permissions + * @param index Index of the permissions array + * @custom:event Emits GrantPermissionsExecuted event + */ + function executeGrantPermissions(uint256 index) external { + uint256 length = grantPermissions[index].length; + for (uint256 i; i < length; ++i) { + Permission memory permission = grantPermissions[index][i]; + ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account); + } + + emit GrantPermissionsExecuted(index); + } + + /* + * @notice Function to execute revoke permissions + * @param index Index of the permissions array + * @custom:event Emits RevokePermissionsExecuted event + */ + function executeRevokePermissions(uint256 index) external { + uint256 length = revokePermissions[index].length; + for (uint256 i; i < length; ++i) { + Permission memory permission = revokePermissions[index][i]; + ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account); + } + + emit RevokePermissionsExecuted(index); + } +} diff --git a/deploy/007-acm-commands-aggregator.ts b/deploy/007-acm-commands-aggregator.ts new file mode 100644 index 00000000..0982ec3b --- /dev/null +++ b/deploy/007-acm-commands-aggregator.ts @@ -0,0 +1,23 @@ +import { ethers } from "hardhat"; +import { DeployFunction } from "hardhat-deploy/types"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const { deployments, getNamedAccounts } = hre; + const { deploy } = deployments; + const { deployer } = await getNamedAccounts(); + + const acm = await ethers.getContract("AccessControlManager"); + + await deploy("ACMCommandsAggregator", { + contract: "ACMCommandsAggregator", + from: deployer, + args: [acm.address], + log: true, + autoMine: true, + }); +}; + +func.tags = ["ACMCommandsAggregator"]; + +export default func; diff --git a/deploy/008-configure-acm-commands-aggregator.ts b/deploy/008-configure-acm-commands-aggregator.ts new file mode 100644 index 00000000..e2837779 --- /dev/null +++ b/deploy/008-configure-acm-commands-aggregator.ts @@ -0,0 +1,785 @@ +import { ethers } from "hardhat"; +import { DeployFunction } from "hardhat-deploy/types"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { ACMCommandsAggregator } from "typechain"; + +const ARBITRUMONE_RESILIENT_ORACLE = "0xd55A98150e0F9f5e3F6280FC25617A5C93d96007"; +const ARBITRUMONE_CHAINLINK_ORACLE = "0x9cd9Fcc7E3dEDA360de7c080590AaD377ac9F113"; +const ARBITRUMONE_REDSTONE_ORACLE = "0xF792C4D3BdeF534D6d1dcC305056D00C95453dD6"; +const ARBITRUMONE_BOUND_VALIDATOR = "0x2245FA2420925Cd3C2D889Ddc5bA1aefEF0E14CF"; +const ETHEREUM_RESILIENT_ORACLE = "0xd2ce3fb018805ef92b8C5976cb31F84b4E295F94"; +const ETHEREUM_CHAINLINK_ORACLE = "0x94c3A2d6B7B2c051aDa041282aec5B0752F8A1F2"; +const ETHEREUM_REDSTONE_ORACLE = "0x0FC8001B2c9Ec90352A46093130e284de5889C86"; +const ETHEREUM_BOUND_VALIDATOR = "0x1Cd5f336A1d28Dff445619CC63d3A0329B4d8a58"; +const ETHEREUM_sFrxETH_ORACLE = "0x5E06A5f48692E4Fff376fDfCA9E4C0183AAADCD1"; +const OPBNBMAINNET_RESILIENT_ORACLE = "0x8f3618c4F0183e14A218782c116fb2438571dAC9"; +const OPBNBMAINNET_BINANCE_ORACLE = "0xB09EC9B628d04E1287216Aa3e2432291f50F9588"; +const OPBNBMAINNET_BOUND_VALIDATOR = "0xd1f80C371C6E2Fa395A5574DB3E3b4dAf43dadCE"; +const ARBITRUMSEPOLIA_RESILIENT_ORACLE = "0x6708bAd042916B47311c8078b29d7f432342102F"; +const ARBITRUMSEPOLIA_CHAINLINK_ORACLE = "0xeDd02c7FfA31490b4107e8f2c25e9198a04F9E45"; +const ARBITRUMSEPOLIA_REDSTONE_ORACLE = "0x15058891ca0c71Bd724b873c41596A682420613C"; +const ARBITRUMSEPOLIA_BOUND_VALIDATOR = "0xfe6bc1545Cc14C131bacA97476D6035ffcC0b889"; +const SEPOLIA_RESILIENT_ORACLE = "0x8000eca36201dddf5805Aa4BeFD73d1EB4D23264"; +const SEPOLIA_CHAINLINK_ORACLE = "0x102F0b714E5d321187A4b6E5993358448f7261cE"; +const SEPOLIA_REDSTONE_ORACLE = "0x4e6269Ef406B4CEE6e67BA5B5197c2FfD15099AE"; +const SEPOLIA_BOUND_VALIDATOR = "0x60c4Aa92eEb6884a76b309Dd8B3731ad514d6f9B"; +const SEPOLIA_sFrxETH_ORACLE = "0x61EB836afA467677e6b403D504fe69D6940e7996"; +const OPBNBTESTNET_RESILIENT_ORACLE = "0xEF4e53a9A4565ef243A2f0ee9a7fc2410E1aA623"; +const OPBNBTESTNET_BINANCE_ORACLE = "0x496B6b03469472572C47bdB407d5549b244a74F2"; +const OPBNBTESTNET_BOUND_VALIDATOR = "0x049537Bb065e6253e9D8D08B45Bf6b753657A746"; + +const ARBITRUMONE_XVS = "0xc1Eb7689147C81aC840d4FF0D298489fc7986d52"; +const ETHEREUM_XVS = "0xd3CC9d8f3689B83c91b7B59cAB4946B063EB894A"; +const OPBNBMAINNET_XVS = "0x3E2e61F1c075881F3fB8dd568043d8c221fd5c61"; +const ARBITRUMSEPOLIA_XVS = "0x877Dc896e7b13096D3827872e396927BbE704407"; +const SEPOLIA_XVS = "0x66ebd019E86e0af5f228a0439EBB33f045CBe63E"; +const OPBNBTESTNET_XVS = "0xc2931B1fEa69b6D6dA65a50363A8D75d285e4da9"; +const ARBITRUMONE_XVS_BRIDGE_ADMIN = "0xf5d81C6F7DAA3F97A6265C8441f92eFda22Ad784"; +const ETHEREUM_XVS_BRIDGE_ADMIN = "0x9C6C95632A8FB3A74f2fB4B7FfC50B003c992b96"; +const OPBNBMAINNET_XVS_BRIDGE_ADMIN = "0x52fcE05aDbf6103d71ed2BA8Be7A317282731831"; +const ARBITRUMSEPOLIA_XVS_BRIDGE_ADMIN = "0xc94578caCC89a29B044a0a1D54d20d48A645E5C8"; +const SEPOLIA_XVS_BRIDGE_ADMIN = "0xd3c6bdeeadB2359F726aD4cF42EAa8B7102DAd9B"; +const OPBNBTESTNET_XVS_BRIDGE_ADMIN = "0x19252AFD0B2F539C400aEab7d460CBFbf74c17ff"; + +const ARBITRUMONE_XVS_VAULT_PROXY = "0x8b79692AAB2822Be30a6382Eb04763A74752d5B4"; +const ETHEREUM_XVS_VAULT_PROXY = "0xA0882C2D5DF29233A092d2887A258C2b90e9b994"; +const OPBNBMAINNET_XVS_VAULT_PROXY = "0x7dc969122450749A8B0777c0e324522d67737988"; +const ARBITRUMSEPOLIA_XVS_VAULT_PROXY = "0x407507DC2809D3aa31D54EcA3BEde5C5c4C8A17F"; +const SEPOLIA_XVS_VAULT_PROXY = "0x1129f882eAa912aE6D4f6D445b2E2b1eCbA99fd5"; +const OPBNBTESTNET_XVS_VAULT_PROXY = "0xB14A0e72C5C202139F78963C9e89252c1ad16f01"; + +const ETHEREUM_XVS_VAULT_TREASURY = "0xaE39C38AF957338b3cEE2b3E5d825ea88df02EfE"; +const SEPOLIA_XVS_VAULT_TREASURY = "0xCCB08e5107b406E67Ad8356023dd489CEbc79B40"; + +const ETHEREUM_POOL_REGISTRY = "0x61CAff113CCaf05FFc6540302c37adcf077C5179"; +const ARBITRUMONE_POOL_REGISTRY = "0x382238f07Bc4Fe4aA99e561adE8A4164b5f815DA"; +const OPBNBMAINNET_POOL_REGISTRY = "0x345a030Ad22e2317ac52811AC41C1A63cfa13aEe"; +const SEPOLIA_POOL_REGISTRY = "0x758f5715d817e02857Ba40889251201A5aE3E186"; +const OPBNBTESTNET_POOL_REGISTRY = "0x560eA4e1cC42591E9f5F5D83Ad2fd65F30128951"; +const ARBITRUMSEPOLIA_POOL_REGISTRY = "0xf93Df3135e0D555185c0BC888073374cA551C5fE"; + +const ARBITRUMONE_PRIME = "0xFE69720424C954A2da05648a0FAC84f9bf11Ef49"; +const ARBITRUMONE_PLP = "0x86bf21dB200f29F21253080942Be8af61046Ec29"; +const ARBITRUMONE_PSR = "0xF9263eaF7eB50815194f26aCcAB6765820B13D41"; +const ETHEREUM_CONVERTER_NETWORK = "0x232CC47AECCC55C2CAcE4372f5B268b27ef7cac8"; +const ETHEREUM_PRIME = "0x14C4525f47A7f7C984474979c57a2Dccb8EACB39"; +const ETHEREUM_PLP = "0x8ba6aFfd0e7Bcd0028D1639225C84DdCf53D8872"; +const ETHEREUM_PSR = "0x8c8c8530464f7D95552A11eC31Adbd4dC4AC4d3E"; +const OPBNBMAINNET_PSR = "0xA2EDD515B75aBD009161B15909C19959484B0C1e"; +const ARBITRUMSEPOLIA_PRIME = "0xadb04ac4942683bc41e27d18234c8dc884786e89"; +const ARBITRUMSEPOLIA_PLP = "0xe82c2c10f55d3268126c29ec813dc6f086904694"; +const ARBITRUMSEPOLIA_PSR = "0x09267d30798B59c581ce54E861A084C6FC298666"; +const SEPOLIA_PRIME = "0x2Ec432F123FEbb114e6fbf9f4F14baF0B1F14AbC"; +const SEPOLIA_PLP = "0x15242a55Ad1842A1aEa09c59cf8366bD2f3CE9B4"; +const SEPOLIA_PSR = "0xbea70755cc3555708ca11219adB0db4C80F6721B"; +const OPBNBTESTNET_PSR = "0xc355dEb1A9289f8C58CFAa076EEdBf51F3A8Da7F"; +const SEPOLIA_CONVERTER_NETWORK = "0xB5A4208bFC4cC2C4670744849B8fC35B21A690Fa"; + +const ARBITRUMONE_GUARDIAN = "0x14e0E151b33f9802b3e75b621c1457afc44DcAA0"; +const ETHEREUM_GUARDIAN = "0x285960C5B22fD66A736C7136967A3eB15e93CC67"; +const OPBNBMAINNET_GUARDIAN = "0xC46796a21a3A9FAB6546aF3434F2eBfFd0604207"; +const SEPOLIA_GUARDIAN = "0x94fa6078b6b8a26f0b6edffbe6501b22a10470fb"; +const OPBNBTESTNET_GUARDIAN = "0xb15f6EfEbC276A3b9805df81b5FB3D50C2A62BDf"; +const ARBITRUMSEPOLIA_GUARDIAN = "0x1426A5Ae009c4443188DA8793751024E358A61C2"; + +const ARBITRUMSEPOLIA_OMNICHAIN_EXECUTOR_OWNER = "0xfCA70dd553b7dF6eB8F813CFEA6a9DD039448878"; +const SEPOLIA_OMNICHAIN_EXECUTOR_OWNER = "0xf964158C67439D01e5f17F0A3F39DfF46823F27A"; +const OPBNBTESTNET_OMNICHAIN_EXECUTOR_OWNER = "0x4F570240FF6265Fbb1C79cE824De6408F1948913"; + +const ETHEREUM_CONVERTERS: string[] = [ + "0xaE39C38AF957338b3cEE2b3E5d825ea88df02EfE", + "0x4f55cb0a24D5542a3478B0E284259A6B850B06BD", + "0xcEB9503f10B781E30213c0b320bCf3b3cE54216E", + "0xDcCDE673Cd8988745dA384A7083B0bd22085dEA0", + "0xb8fD67f215117FADeF06447Af31590309750529D", + "0x1FD30e761C3296fE36D9067b1e398FD97B4C0407", +]; +const SEPOLIA_CONVERTERS: string[] = [ + "0xCCB08e5107b406E67Ad8356023dd489CEbc79B40", + "0x3716C24EA86A67cAf890d7C9e4C4505cDDC2F8A2", + "0x511a559a699cBd665546a1F75908f7E9454Bfc67", + "0x8a3937F27921e859db3FDA05729CbCea8cfd82AE", + "0x274a834eFFA8D5479502dD6e78925Bc04ae82B46", + "0xc203bfA9dCB0B5fEC510Db644A494Ff7f4968ed2", +]; + +enum AccountType { + NORMAL_TIMELOCK = "NormalTimelock", + FAST_TRACK_TIMELOCK = "FastTrackTimelock", + CRITICAL_TIMELOCK = "CriticalTimelock", +} + +interface Permissions { + [key: string]: string[][]; +} + +const accounts = [AccountType.NORMAL_TIMELOCK] + .concat(AccountType.CRITICAL_TIMELOCK) + .concat(AccountType.FAST_TRACK_TIMELOCK); + +const getResilientOraclePermissions = (resilientOracle: string): string[][] => { + return [ + accounts.flatMap(timelock => [resilientOracle, "pause()", timelock]), + accounts.flatMap(timelock => [resilientOracle, "unpause()", timelock]), + accounts.flatMap(timelock => [resilientOracle, "setTokenConfig(TokenConfig)", timelock]), + [resilientOracle, "setOracle(address,address,uint8)", AccountType.NORMAL_TIMELOCK], + [resilientOracle, "enableOracle(address,uint8,bool)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getChainlinkOraclePermissions = (chainlinkOracle: string): string[][] => { + return [ + accounts.flatMap(timelock => [chainlinkOracle, "setTokenConfig(TokenConfig)", timelock]), + accounts.flatMap(timelock => [chainlinkOracle, "setDirectPrice(address,uint256)", timelock]), + ]; +}; + +const getRedstoneOraclePermissions = (redstoneOracle: string): string[][] => { + return [ + accounts.flatMap(timelock => [redstoneOracle, "setTokenConfig(TokenConfig)", timelock]), + accounts.flatMap(timelock => [redstoneOracle, "setDirectPrice(address,uint256)", timelock]), + ]; +}; + +const getBoundValidatorPermissions = (boundValidator: string): string[][] => { + return [[boundValidator, "setValidateConfig(ValidateConfig)", AccountType.NORMAL_TIMELOCK]]; +}; + +const getSFrxETHOraclePermissions = (sFrxETHOracle: string): string[][] => { + return [accounts.flatMap(timelock => [sFrxETHOracle, "setMaxAllowedPriceDifference(uint256)", timelock])]; +}; + +const getBinanceOraclePermissions = (binanceOracle: string): string[][] => { + return [ + accounts.flatMap(timelock => [binanceOracle, "setMaxStalePeriod(string,uint256)", timelock]), + accounts.flatMap(timelock => [binanceOracle, "setSymbolOverride(string,string)", timelock]), + ]; +}; + +const getXVSPermissions = (xvs: string): string[][] => { + return [ + accounts.flatMap(timelock => [xvs, "migrateMinterTokens(address,address)", timelock]), + accounts.flatMap(timelock => [xvs, "setMintCap(address,uint256)", timelock]), + accounts.flatMap(timelock => [xvs, "updateBlacklist(address,bool)", timelock]), + accounts.flatMap(timelock => [xvs, "pause()", timelock]), + accounts.flatMap(timelock => [xvs, "unpause()", timelock]), + ]; +}; + +const getXVSBridgeAdminPermissions = (xvsBridgeAdmin: string): string[][] => { + return [ + accounts.flatMap(timelock => [xvsBridgeAdmin, "setSendVersion(uint16)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "setReceiveVersion(uint16)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "forceResumeReceive(uint16,bytes)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "setMaxSingleTransactionLimit(uint16,uint256)", timelock]), + [xvsBridgeAdmin, "setOracle(address)", AccountType.NORMAL_TIMELOCK], + accounts.flatMap(timelock => [xvsBridgeAdmin, "setMaxDailyLimit(uint16,uint256)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "setMaxSingleReceiveTransactionLimit(uint16,uint256)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "setMaxDailyReceiveLimit(uint16,uint256)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "pause()", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "unpause()", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "removeTrustedRemote(uint16)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "dropFailedMessage(uint16,bytes,uint64)", timelock]), + [xvsBridgeAdmin, "setPrecrime(address)", AccountType.NORMAL_TIMELOCK], + accounts.flatMap(timelock => [xvsBridgeAdmin, "setMinDstGas(uint16,uint16,uint256)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "setPayloadSizeLimit(uint16,uint256)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "setWhitelist(address,bool)", timelock]), + accounts.flatMap(timelock => [xvsBridgeAdmin, "setConfig(uint16,uint16,uint256,bytes)", timelock]), + [xvsBridgeAdmin, "sweepToken(address,address,uint256)", AccountType.NORMAL_TIMELOCK], + accounts.flatMap(timelock => [xvsBridgeAdmin, "updateSendAndCallEnabled(bool)", timelock]), + [xvsBridgeAdmin, "setTrustedRemoteAddress(uint16,bytes)", AccountType.NORMAL_TIMELOCK], + [xvsBridgeAdmin, "transferBridgeOwnership(address)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getXVSVaultPermissions = (xvsVault: string): string[][] => { + return [ + [xvsVault, "pause()", AccountType.CRITICAL_TIMELOCK], + [xvsVault, "resume()", AccountType.CRITICAL_TIMELOCK], + [xvsVault, "setRewardAmountPerBlockOrSecond(address,uint256)", AccountType.CRITICAL_TIMELOCK], + [xvsVault, "pause()", AccountType.FAST_TRACK_TIMELOCK], + [xvsVault, "resume()", AccountType.FAST_TRACK_TIMELOCK], + [xvsVault, "setRewardAmountPerBlockOrSecond(address,uint256)", AccountType.FAST_TRACK_TIMELOCK], + [xvsVault, "pause()", AccountType.NORMAL_TIMELOCK], + [xvsVault, "resume()", AccountType.NORMAL_TIMELOCK], + [xvsVault, "add(address,uint256,address,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + [xvsVault, "set(address,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + [xvsVault, "setRewardAmountPerBlockOrSecond(address,uint256)", AccountType.NORMAL_TIMELOCK], + [xvsVault, "setWithdrawalLockingPeriod(address,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getPoolRegistryPermissions = (poolRegistry: string): string[][] => { + return [ + [poolRegistry, "addPool(string,address,uint256,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + [poolRegistry, "addMarket(AddMarketInput)", AccountType.NORMAL_TIMELOCK], + [poolRegistry, "setPoolName(address,string)", AccountType.NORMAL_TIMELOCK], + [poolRegistry, "updatePoolMetadata(address,VenusPoolMetaData)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getPrimePermissions = (prime: string): string[][] => { + return [ + accounts.flatMap(timelock => [prime, "updateAlpha(uint128,uint128)", timelock]), + accounts.flatMap(timelock => [prime, "updateMultipliers(address,uint256,uint256)", timelock]), + accounts.flatMap(timelock => [prime, "setStakedAt(address[],uint256[])", timelock]), + accounts.flatMap(timelock => [prime, "addMarket(address,address,uint256,uint256)", timelock]), + accounts.flatMap(timelock => [prime, "setLimit(uint256,uint256)", timelock]), + accounts.flatMap(timelock => [prime, "setMaxLoopsLimit(uint256)", timelock]), + accounts.flatMap(timelock => [prime, "issue(bool,address[])", timelock]), + accounts.flatMap(timelock => [prime, "burn(address)", timelock]), + accounts.flatMap(timelock => [prime, "togglePause()", timelock]), + ]; +}; + +const getPrimeLiquidityProviderPermissions = (primeLiquidityProvider: string): string[][] => { + return [ + accounts.flatMap(timelock => [primeLiquidityProvider, "setTokensDistributionSpeed(address[],uint256[])", timelock]), + accounts.flatMap(timelock => [ + primeLiquidityProvider, + "setMaxTokensDistributionSpeed(address[],uint256[])", + timelock, + ]), + accounts.flatMap(timelock => [primeLiquidityProvider, "setMaxLoopsLimit(uint256)", timelock]), + accounts.flatMap(timelock => [primeLiquidityProvider, "pauseFundsTransfer()", timelock]), + accounts.flatMap(timelock => [primeLiquidityProvider, "resumeFundsTransfer()", timelock]), + ]; +}; + +const getProtocolShareReservePermissions = (protocolShareReserve: string): string[][] => { + return [ + accounts.flatMap(timelock => [ + protocolShareReserve, + "addOrUpdateDistributionConfigs(DistributionConfig[])", + timelock, + ]), + accounts.flatMap(timelock => [protocolShareReserve, "removeDistributionConfig(Schema,address)", timelock]), + ]; +}; + +const getConverterNetworkPermissions = (converterNetwork: string): string[][] => { + return [ + accounts.flatMap(timelock => [converterNetwork, "addTokenConverter(address)", timelock]), + accounts.flatMap(timelock => [converterNetwork, "removeTokenConverter(address)", timelock]), + ]; +}; + +const getComptrollerPermissions = (): string[][] => { + return [ + accounts.flatMap(timelock => [ + ethers.constants.AddressZero, + "setCollateralFactor(address,uint256,uint256)", + timelock, + ]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "setMarketBorrowCaps(address[],uint256[])", timelock]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "setMarketSupplyCaps(address[],uint256[])", timelock]), + accounts.flatMap(timelock => [ + ethers.constants.AddressZero, + "setActionsPaused(address[],uint256[],bool)", + timelock, + ]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "setForcedLiquidation(address,bool)", timelock]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "unlistMarket(address)", timelock]), + [ethers.constants.AddressZero, "setCloseFactor(uint256)", AccountType.NORMAL_TIMELOCK], + [ethers.constants.AddressZero, "setLiquidationIncentive(uint256)", AccountType.NORMAL_TIMELOCK], + [ethers.constants.AddressZero, "setMinLiquidatableCollateral(uint256)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getVTokenPermissions = (): string[][] => { + return [ + accounts.flatMap(timelock => [ethers.constants.AddressZero, "setReserveFactor(uint256)", timelock]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "setInterestRateModel(address)", timelock]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "setReduceReservesBlockDelta(uint256)", timelock]), + [ethers.constants.AddressZero, "setProtocolSeizeShare(uint256)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getRewardDistributorPermissionsTimebased = (): string[][] => { + return [ + [ethers.constants.AddressZero, "setRewardTokenSpeeds(address[],uint256[],uint256[])", AccountType.NORMAL_TIMELOCK], + [ + ethers.constants.AddressZero, + "setLastRewardingBlockTimestamps(address[],uint256[],uint256[])", + AccountType.NORMAL_TIMELOCK, + ], + ]; +}; + +const getRewardDistributorPermissionsBlockbased = (): string[][] => { + return [ + [ethers.constants.AddressZero, "setRewardTokenSpeeds(address[],uint256[],uint256[])", AccountType.NORMAL_TIMELOCK], + [ethers.constants.AddressZero, "setLastRewardingBlocks(address[],uint32[],uint32[])", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getIRMPermissions = (): string[][] => { + return [ + [ethers.constants.AddressZero, "updateJumpRateModel(uint256,uint256,uint256,uint256)", AccountType.NORMAL_TIMELOCK], + ]; +}; + +const getConverterPermissions = (): string[][] => { + return [ + accounts.flatMap(timelock => [ethers.constants.AddressZero, "pauseConversion()", timelock]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "resumeConversion()", timelock]), + accounts.flatMap(timelock => [ethers.constants.AddressZero, "setMinAmountToConvert(uint256)", timelock]), + accounts.flatMap(timelock => [ + ethers.constants.AddressZero, + "setConversionConfig(address,address,ConversionConfig)", + timelock, + ]), + ]; +}; + +const getXVSVaultTreasuryPermissions = (xvsVaultTreasury: string): string[][] => { + return [accounts.flatMap(timelock => [xvsVaultTreasury, "fundXVSVault(uint256)", timelock])]; +}; + +const getOmniChainExecutorOwnerPermissions = (omniChainExecutor: string, guardian: string): string[][] => { + return [ + [omniChainExecutor, "setSrcChainId(uint16)", AccountType.NORMAL_TIMELOCK], + [omniChainExecutor, "transferBridgeOwnership(address)", AccountType.NORMAL_TIMELOCK], + [omniChainExecutor, "setSrcChainId(uint16)", guardian], + [omniChainExecutor, "transferBridgeOwnership(address)", guardian], + ]; +}; + +const getXVSBridgeAdminRevokePermissions = (xvsBridgeAdmin: string, guardian: string): string[][] => { + return [ + [xvsBridgeAdmin, "setSendVersion(uint16)", guardian], + [xvsBridgeAdmin, "setReceiveVersion(uint16)", guardian], + [xvsBridgeAdmin, "forceResumeReceive(uint16,bytes)", guardian], + [xvsBridgeAdmin, "setOracle(address)", guardian], + [xvsBridgeAdmin, "removeTrustedRemote(uint16)", guardian], + [xvsBridgeAdmin, "dropFailedMessage(uint16,bytes,uint64)", guardian], + [xvsBridgeAdmin, "setPrecrime(address)", guardian], + [xvsBridgeAdmin, "setMinDstGas(uint16,uint16,uint256)", guardian], + [xvsBridgeAdmin, "setPayloadSizeLimit(uint16,uint256)", guardian], + [xvsBridgeAdmin, "setWhitelist(address,bool)", guardian], + [xvsBridgeAdmin, "setConfig(uint16,uint16,uint256,bytes)", guardian], + [xvsBridgeAdmin, "sweepToken(address,address,uint256)", guardian], + [xvsBridgeAdmin, "updateSendAndCallEnabled(bool)", guardian], + [xvsBridgeAdmin, "setTrustedRemoteAddress(uint16,bytes)", guardian], + [xvsBridgeAdmin, "transferBridgeOwnership(address)", guardian], + ]; +}; + +const getXVSVaultTreasuryRevokePermissions = (xvsVaultTreasury: string, guardian: string): string[][] => { + return [[xvsVaultTreasury, "fundXVSVault(uint256)", guardian]]; +}; + +const getPrimeRevokePermissions = (prime: string, guardian: string): string[][] => { + return [ + [prime, "updateAlpha(uint128,uint128)", guardian], + [prime, "updateMultipliers(address,uint256,uint256)", guardian], + [prime, "setStakedAt(address[],uint256[])", guardian], + [prime, "addMarket(address,address,uint256,uint256)", guardian], + [prime, "setLimit(uint256,uint256)", guardian], + [prime, "setMaxLoopsLimit(uint256)", guardian], + [prime, "issue(bool,address[])", guardian], + [prime, "burn(address)", guardian], + ]; +}; + +const getPrimeLiquidityProviderRevokePermissions = (primeLiquidityProvider: string, guardian: string): string[][] => { + return [ + [primeLiquidityProvider, "setTokensDistributionSpeed(address[],uint256[])", guardian], + [primeLiquidityProvider, "setMaxTokensDistributionSpeed(address[],uint256[])", guardian], + [primeLiquidityProvider, "setMaxLoopsLimit(uint256)", guardian], + ]; +}; + +const getResilientOracleRevokePermissions = (resilientOracle: string, guardian: string): string[][] => { + return [ + [resilientOracle, "setOracle(address,address,uint8)", guardian], + [resilientOracle, "enableOracle(address,uint8,bool)", guardian], + ]; +}; + +const getBoundValidatorRevokePermissions = (boundValidator: string, guardian: string): string[][] => { + return [[boundValidator, "setValidateConfig(ValidateConfig)", guardian]]; +}; + +const getXVSVaultRevokePermissions = (xvsVault: string, guardian: string): string[][] => { + return [ + [xvsVault, "add(address,uint256,address,uint256,uint256)", guardian], + [xvsVault, "set(address,uint256,uint256)", guardian], + [xvsVault, "setRewardAmountPerBlockOrSecond(address,uint256)", guardian], + [xvsVault, "setWithdrawalLockingPeriod(address,uint256,uint256)", guardian], + ]; +}; + +const getRewardDistributorRevokePermissions = (guardian: string, lastRewardingBlockTimestamp: boolean): string[][] => { + const permissions = [ + [ethers.constants.AddressZero, "setLastRewardingBlock(address[],uint32[],uint32[])", guardian], + [ethers.constants.AddressZero, "setLastRewardingBlocks(address[],uint32[],uint32[])", guardian], + [ethers.constants.AddressZero, "setRewardTokenSpeeds(address[],uint256[],uint256[])", guardian], + ]; + if (lastRewardingBlockTimestamp) { + permissions.push([ + ethers.constants.AddressZero, + "setLastRewardingBlockTimestamps(address[],uint256[],uint256[])", + guardian, + ]); + } + return permissions; +}; + +const getIRMRevokePermissions = (guardian: string): string[][] => { + return [[ethers.constants.AddressZero, "updateJumpRateModel(uint256,uint256,uint256,uint256)", guardian]]; +}; + +const getPoolRegistryRevokePermissions = (poolRegistry: string, guardian: string): string[][] => { + if (poolRegistry === OPBNBTESTNET_POOL_REGISTRY || poolRegistry === ARBITRUMSEPOLIA_POOL_REGISTRY) { + return [ + [ethers.constants.AddressZero, "addPool(string,address,uint256,uint256,uint256)", guardian], + [ethers.constants.AddressZero, "addMarket(AddMarketInput)", guardian], + [ethers.constants.AddressZero, "setPoolName(address,string)", guardian], + [ethers.constants.AddressZero, "updatePoolMetadata(address,VenusPoolMetaData)", guardian], + ]; + } else { + return [ + [poolRegistry, "addPool(string,address,uint256,uint256,uint256)", guardian], + [poolRegistry, "addMarket(AddMarketInput)", guardian], + [poolRegistry, "setPoolName(address,string)", guardian], + [poolRegistry, "updatePoolMetadata(address,VenusPoolMetaData)", guardian], + ]; + } +}; + +const getComptrollerRevokePermissions = (guardian: string): string[][] => { + return [ + [ethers.constants.AddressZero, "setCloseFactor(uint256)", guardian], + [ethers.constants.AddressZero, "setLiquidationIncentive(uint256)", guardian], + [ethers.constants.AddressZero, "setMinLiquidatableCollateral(uint256)", guardian], + [ethers.constants.AddressZero, "setForcedLiquidation(address,bool)", guardian], + ]; +}; + +const getVTokenRevokePermissions = (guardian: string): string[][] => { + return [ + [ethers.constants.AddressZero, "setProtocolSeizeShare(uint256)", guardian], + [ethers.constants.AddressZero, "setReserveFactor(uint256)", guardian], + [ethers.constants.AddressZero, "setInterestRateModel(address)", guardian], + [ethers.constants.AddressZero, "setReduceReservesBlockDelta(uint256)", guardian], + ]; +}; + +const getRedstoneOracleRevokePermissions = (redstoneOracle: string, guardian: string): string[][] => { + return [ + [redstoneOracle, "setTokenConfig(TokenConfig)", guardian], + [redstoneOracle, "setDirectPrice(address,uint256)", guardian], + ]; +}; + +const getConverterNetworkRevokePermissions = (converterNetwork: string, guardian: string): string[][] => { + return [ + [converterNetwork, "addTokenConverter(address)", guardian], + [converterNetwork, "removeTokenConverter(address)", guardian], + ]; +}; + +const getSFrxETHOracleRevokePermissions = (sFrxETHOracle: string, guardian: string): string[][] => { + return [[sFrxETHOracle, "setMaxAllowedPriceDifference(uint256)", guardian]]; +}; + +const getConvertersRevokePermissions = (converters: string[], guardian: string): string[][] => { + return [ + converters.flatMap(converter => [converter, "setMinAmountToConvert(uint256)", guardian]), + converters.flatMap(converter => [converter, "setConversionConfig(address,address,ConversionConfig)", guardian]), + ]; +}; + +const getOmniChainExecutorOwnerRevokePermissions = (omniChainExecutor: string, guardian: string): string[][] => { + return [ + [omniChainExecutor, "setTrustedRemoteAddress(uint16,bytes)", AccountType.CRITICAL_TIMELOCK], + [omniChainExecutor, "setTimelockPendingAdmin(address,uint8)", AccountType.CRITICAL_TIMELOCK], + [omniChainExecutor, "setGuardian(address)", AccountType.CRITICAL_TIMELOCK], + [omniChainExecutor, "setTrustedRemoteAddress(uint16,bytes)", AccountType.FAST_TRACK_TIMELOCK], + [omniChainExecutor, "setTimelockPendingAdmin(address,uint8)", AccountType.FAST_TRACK_TIMELOCK], + [omniChainExecutor, "setGuardian(address)", AccountType.FAST_TRACK_TIMELOCK], + [omniChainExecutor, "setSendVersion(uint16)", guardian], + [omniChainExecutor, "setPrecrime(address)", guardian], + [omniChainExecutor, "setMinDstGas(uint16,uint16,uint256)", guardian], + [omniChainExecutor, "setPayloadSizeLimit(uint16,uint256)", guardian], + ]; +}; + +const grantPermissions: Permissions = { + arbitrumone: [ + ...getResilientOraclePermissions(ARBITRUMONE_RESILIENT_ORACLE), + ...getChainlinkOraclePermissions(ARBITRUMONE_CHAINLINK_ORACLE), + ...getRedstoneOraclePermissions(ARBITRUMONE_REDSTONE_ORACLE), + ...getBoundValidatorPermissions(ARBITRUMONE_BOUND_VALIDATOR), + ...getXVSPermissions(ARBITRUMONE_XVS), + ...getXVSBridgeAdminPermissions(ARBITRUMONE_XVS_BRIDGE_ADMIN), + ...getXVSVaultPermissions(ARBITRUMONE_XVS_VAULT_PROXY), + ...getPoolRegistryPermissions(ARBITRUMONE_POOL_REGISTRY), + ...getPrimePermissions(ARBITRUMONE_PRIME), + ...getPrimeLiquidityProviderPermissions(ARBITRUMONE_PLP), + ...getProtocolShareReservePermissions(ARBITRUMONE_PSR), + ...getComptrollerPermissions(), + ...getVTokenPermissions(), + ...getRewardDistributorPermissionsTimebased(), + ...getIRMPermissions(), + ], + ethereum: [ + ...getResilientOraclePermissions(ETHEREUM_RESILIENT_ORACLE), + ...getChainlinkOraclePermissions(ETHEREUM_CHAINLINK_ORACLE), + ...getRedstoneOraclePermissions(ETHEREUM_REDSTONE_ORACLE), + ...getBoundValidatorPermissions(ETHEREUM_BOUND_VALIDATOR), + ...getSFrxETHOraclePermissions(ETHEREUM_sFrxETH_ORACLE), + ...getXVSPermissions(ETHEREUM_XVS), + ...getXVSBridgeAdminPermissions(ETHEREUM_XVS_BRIDGE_ADMIN), + ...getXVSVaultPermissions(ETHEREUM_XVS_VAULT_PROXY), + ...getPoolRegistryPermissions(ETHEREUM_POOL_REGISTRY), + ...getPrimePermissions(ETHEREUM_PRIME), + ...getPrimeLiquidityProviderPermissions(ETHEREUM_PLP), + ...getProtocolShareReservePermissions(ETHEREUM_PSR), + ...getConverterNetworkPermissions(ETHEREUM_CONVERTER_NETWORK), + ...getComptrollerPermissions(), + ...getVTokenPermissions(), + ...getRewardDistributorPermissionsBlockbased(), + ...getIRMPermissions(), + ...getConverterPermissions(), + ...getXVSVaultTreasuryPermissions(ETHEREUM_XVS_VAULT_TREASURY), + ], + opbnbmainnet: [ + ...getResilientOraclePermissions(OPBNBMAINNET_RESILIENT_ORACLE), + ...getBoundValidatorPermissions(OPBNBMAINNET_BOUND_VALIDATOR), + ...getBinanceOraclePermissions(OPBNBMAINNET_BINANCE_ORACLE), + ...getXVSPermissions(OPBNBMAINNET_XVS), + ...getXVSBridgeAdminPermissions(OPBNBMAINNET_XVS_BRIDGE_ADMIN), + ...getXVSVaultPermissions(OPBNBMAINNET_XVS_VAULT_PROXY), + ...getPoolRegistryPermissions(OPBNBMAINNET_POOL_REGISTRY), + ...getProtocolShareReservePermissions(OPBNBMAINNET_PSR), + ...getComptrollerPermissions(), + ...getVTokenPermissions(), + ...getIRMPermissions(), + ], + arbitrumsepolia: [ + ...getResilientOraclePermissions(ARBITRUMSEPOLIA_RESILIENT_ORACLE), + ...getChainlinkOraclePermissions(ARBITRUMSEPOLIA_CHAINLINK_ORACLE), + ...getRedstoneOraclePermissions(ARBITRUMSEPOLIA_REDSTONE_ORACLE), + ...getBoundValidatorPermissions(ARBITRUMSEPOLIA_BOUND_VALIDATOR), + ...getXVSPermissions(ARBITRUMSEPOLIA_XVS), + ...getXVSBridgeAdminPermissions(ARBITRUMSEPOLIA_XVS_BRIDGE_ADMIN), + ...getXVSVaultPermissions(ARBITRUMSEPOLIA_XVS_VAULT_PROXY), + ...getPoolRegistryPermissions(ARBITRUMSEPOLIA_POOL_REGISTRY), + ...getPrimePermissions(ARBITRUMSEPOLIA_PRIME), + ...getPrimeLiquidityProviderPermissions(ARBITRUMSEPOLIA_PLP), + ...getProtocolShareReservePermissions(ARBITRUMSEPOLIA_PSR), + ...getComptrollerPermissions(), + ...getVTokenPermissions(), + ...getRewardDistributorPermissionsTimebased(), + ...getIRMPermissions(), + ...getOmniChainExecutorOwnerPermissions(ARBITRUMSEPOLIA_OMNICHAIN_EXECUTOR_OWNER, ARBITRUMSEPOLIA_GUARDIAN), + ], + sepolia: [ + ...getResilientOraclePermissions(SEPOLIA_RESILIENT_ORACLE), + ...getResilientOraclePermissions(SEPOLIA_CHAINLINK_ORACLE), + ...getRedstoneOraclePermissions(SEPOLIA_REDSTONE_ORACLE), + ...getBoundValidatorPermissions(SEPOLIA_BOUND_VALIDATOR), + ...getSFrxETHOraclePermissions(SEPOLIA_sFrxETH_ORACLE), + ...getXVSPermissions(SEPOLIA_XVS), + ...getXVSBridgeAdminPermissions(SEPOLIA_XVS_BRIDGE_ADMIN), + ...getXVSVaultPermissions(SEPOLIA_XVS_VAULT_PROXY), + ...getPoolRegistryPermissions(SEPOLIA_POOL_REGISTRY), + ...getPrimePermissions(SEPOLIA_PRIME), + ...getPrimeLiquidityProviderPermissions(SEPOLIA_PLP), + ...getProtocolShareReservePermissions(SEPOLIA_PSR), + ...getConverterNetworkPermissions(SEPOLIA_CONVERTER_NETWORK), + ...getComptrollerPermissions(), + ...getVTokenPermissions(), + ...getRewardDistributorPermissionsBlockbased(), + ...getIRMPermissions(), + ...getConverterPermissions(), + ...getXVSVaultTreasuryPermissions(SEPOLIA_XVS_VAULT_TREASURY), + ...getOmniChainExecutorOwnerPermissions(SEPOLIA_OMNICHAIN_EXECUTOR_OWNER, SEPOLIA_GUARDIAN), + ], + opbnbtestnet: [ + ...getResilientOraclePermissions(OPBNBTESTNET_RESILIENT_ORACLE), + ...getResilientOraclePermissions(OPBNBTESTNET_BOUND_VALIDATOR), + ...getBinanceOraclePermissions(OPBNBTESTNET_BINANCE_ORACLE), + ...getXVSPermissions(OPBNBTESTNET_XVS), + ...getXVSBridgeAdminPermissions(OPBNBTESTNET_XVS_BRIDGE_ADMIN), + ...getXVSVaultPermissions(OPBNBTESTNET_XVS_VAULT_PROXY), + ...getPoolRegistryPermissions(OPBNBTESTNET_POOL_REGISTRY), + ...getProtocolShareReservePermissions(OPBNBTESTNET_PSR), + ...getComptrollerPermissions(), + ...getVTokenPermissions(), + ...getIRMPermissions(), + ...getOmniChainExecutorOwnerPermissions(OPBNBTESTNET_OMNICHAIN_EXECUTOR_OWNER, OPBNBTESTNET_GUARDIAN), + ], +}; + +const revokePermissions: Permissions = { + arbitrumone: [ + ...getPrimeRevokePermissions(ARBITRUMONE_PRIME, ARBITRUMONE_GUARDIAN), + ...getPrimeLiquidityProviderRevokePermissions(ARBITRUMONE_PLP, ARBITRUMONE_GUARDIAN), + ...getResilientOracleRevokePermissions(ARBITRUMONE_RESILIENT_ORACLE, ARBITRUMONE_GUARDIAN), + ...getBoundValidatorRevokePermissions(ARBITRUMONE_BOUND_VALIDATOR, ARBITRUMONE_GUARDIAN), + ...getXVSVaultRevokePermissions(ARBITRUMONE_XVS, ARBITRUMONE_GUARDIAN), + ...getRewardDistributorRevokePermissions(ARBITRUMONE_GUARDIAN, true), + ...getIRMRevokePermissions(ARBITRUMONE_GUARDIAN), + ...getPoolRegistryRevokePermissions(ARBITRUMONE_POOL_REGISTRY, ARBITRUMONE_GUARDIAN), + ...getComptrollerRevokePermissions(ARBITRUMONE_GUARDIAN), + ...getVTokenRevokePermissions(ARBITRUMONE_GUARDIAN), + ...getXVSBridgeAdminRevokePermissions(ARBITRUMONE_XVS_BRIDGE_ADMIN, ARBITRUMONE_GUARDIAN), + ...getRedstoneOracleRevokePermissions(ARBITRUMONE_REDSTONE_ORACLE, ARBITRUMONE_GUARDIAN), + ], + ethereum: [ + ...getPrimeRevokePermissions(ETHEREUM_PRIME, ETHEREUM_GUARDIAN), + ...getPrimeLiquidityProviderRevokePermissions(ETHEREUM_PLP, ETHEREUM_GUARDIAN), + ...getResilientOracleRevokePermissions(ETHEREUM_RESILIENT_ORACLE, ETHEREUM_GUARDIAN), + ...getBoundValidatorRevokePermissions(ETHEREUM_BOUND_VALIDATOR, ETHEREUM_GUARDIAN), + ...getXVSVaultRevokePermissions(ETHEREUM_XVS, ETHEREUM_GUARDIAN), + ...getRewardDistributorRevokePermissions(ETHEREUM_GUARDIAN, false), + ...getIRMRevokePermissions(ETHEREUM_GUARDIAN), + ...getPoolRegistryRevokePermissions(ETHEREUM_POOL_REGISTRY, ETHEREUM_GUARDIAN), + ...getComptrollerRevokePermissions(ETHEREUM_GUARDIAN), + ...getVTokenRevokePermissions(ETHEREUM_GUARDIAN), + ...getRedstoneOracleRevokePermissions(ETHEREUM_REDSTONE_ORACLE, ETHEREUM_GUARDIAN), + ...getConverterNetworkRevokePermissions(ETHEREUM_CONVERTER_NETWORK, ETHEREUM_GUARDIAN), + ...getSFrxETHOracleRevokePermissions(ETHEREUM_sFrxETH_ORACLE, ETHEREUM_GUARDIAN), + ...getConvertersRevokePermissions(ETHEREUM_CONVERTERS, ETHEREUM_GUARDIAN), + ...getXVSVaultTreasuryRevokePermissions(ETHEREUM_XVS_VAULT_TREASURY, ETHEREUM_GUARDIAN), + ...getXVSBridgeAdminRevokePermissions(ETHEREUM_XVS_BRIDGE_ADMIN, ETHEREUM_GUARDIAN), + ], + opbnbmainnet: [ + ...getResilientOracleRevokePermissions(OPBNBMAINNET_RESILIENT_ORACLE, OPBNBMAINNET_GUARDIAN), + ...getBoundValidatorRevokePermissions(OPBNBMAINNET_BOUND_VALIDATOR, OPBNBMAINNET_GUARDIAN), + ...getXVSVaultRevokePermissions(OPBNBMAINNET_XVS, OPBNBMAINNET_GUARDIAN), + ...getIRMRevokePermissions(OPBNBMAINNET_GUARDIAN), + ...getPoolRegistryRevokePermissions(OPBNBMAINNET_POOL_REGISTRY, OPBNBMAINNET_GUARDIAN), + ...getComptrollerRevokePermissions(OPBNBMAINNET_GUARDIAN), + ...getVTokenRevokePermissions(OPBNBMAINNET_GUARDIAN), + ...getXVSBridgeAdminRevokePermissions(OPBNBMAINNET_XVS_BRIDGE_ADMIN, OPBNBMAINNET_GUARDIAN), + ], + opbnbtestnet: [ + ...getResilientOracleRevokePermissions(OPBNBTESTNET_RESILIENT_ORACLE, OPBNBTESTNET_GUARDIAN), + ...getBoundValidatorRevokePermissions(OPBNBTESTNET_BOUND_VALIDATOR, OPBNBTESTNET_GUARDIAN), + ...getXVSVaultRevokePermissions(OPBNBTESTNET_XVS, OPBNBTESTNET_GUARDIAN), + ...getIRMRevokePermissions(OPBNBTESTNET_GUARDIAN), + ...getPoolRegistryRevokePermissions(OPBNBTESTNET_POOL_REGISTRY, OPBNBTESTNET_GUARDIAN), + ...getComptrollerRevokePermissions(OPBNBTESTNET_GUARDIAN), + ...getVTokenRevokePermissions(OPBNBTESTNET_GUARDIAN), + ...getXVSBridgeAdminRevokePermissions(OPBNBTESTNET_XVS_BRIDGE_ADMIN, OPBNBTESTNET_GUARDIAN), + ...getRewardDistributorRevokePermissions(OPBNBTESTNET_GUARDIAN, false), + ...getOmniChainExecutorOwnerRevokePermissions(OPBNBTESTNET_OMNICHAIN_EXECUTOR_OWNER, OPBNBTESTNET_GUARDIAN), + ], + sepolia: [ + ...getPrimeRevokePermissions(SEPOLIA_PRIME, SEPOLIA_GUARDIAN), + ...getPrimeLiquidityProviderRevokePermissions(SEPOLIA_PLP, SEPOLIA_GUARDIAN), + ...getResilientOracleRevokePermissions(SEPOLIA_RESILIENT_ORACLE, SEPOLIA_GUARDIAN), + ...getBoundValidatorRevokePermissions(SEPOLIA_BOUND_VALIDATOR, SEPOLIA_GUARDIAN), + ...getXVSVaultRevokePermissions(SEPOLIA_XVS, SEPOLIA_GUARDIAN), + ...getRewardDistributorRevokePermissions(SEPOLIA_GUARDIAN, false), + ...getIRMRevokePermissions(SEPOLIA_GUARDIAN), + ...getPoolRegistryRevokePermissions(SEPOLIA_POOL_REGISTRY, SEPOLIA_GUARDIAN), + ...getComptrollerRevokePermissions(SEPOLIA_GUARDIAN), + ...getVTokenRevokePermissions(SEPOLIA_GUARDIAN), + ...getRedstoneOracleRevokePermissions(SEPOLIA_REDSTONE_ORACLE, SEPOLIA_GUARDIAN), + ...getConverterNetworkRevokePermissions(SEPOLIA_CONVERTER_NETWORK, SEPOLIA_GUARDIAN), + ...getSFrxETHOracleRevokePermissions(SEPOLIA_sFrxETH_ORACLE, SEPOLIA_GUARDIAN), + ...getConvertersRevokePermissions(SEPOLIA_CONVERTERS, SEPOLIA_GUARDIAN), + ...getXVSVaultTreasuryRevokePermissions(SEPOLIA_XVS_VAULT_TREASURY, SEPOLIA_GUARDIAN), + ...getXVSBridgeAdminRevokePermissions(SEPOLIA_XVS_BRIDGE_ADMIN, SEPOLIA_GUARDIAN), + ...getOmniChainExecutorOwnerRevokePermissions(SEPOLIA_OMNICHAIN_EXECUTOR_OWNER, SEPOLIA_GUARDIAN), + ], + arbitrumsepolia: [ + ...getPrimeRevokePermissions(ARBITRUMSEPOLIA_PRIME, ARBITRUMSEPOLIA_GUARDIAN), + ...getPrimeLiquidityProviderRevokePermissions(ARBITRUMSEPOLIA_PLP, ARBITRUMSEPOLIA_GUARDIAN), + ...getResilientOracleRevokePermissions(ARBITRUMSEPOLIA_RESILIENT_ORACLE, ARBITRUMSEPOLIA_GUARDIAN), + ...getBoundValidatorRevokePermissions(ARBITRUMSEPOLIA_BOUND_VALIDATOR, ARBITRUMSEPOLIA_GUARDIAN), + ...getXVSVaultRevokePermissions(ARBITRUMSEPOLIA_XVS, ARBITRUMSEPOLIA_GUARDIAN), + ...getRewardDistributorRevokePermissions(ARBITRUMSEPOLIA_GUARDIAN, true), + ...getIRMRevokePermissions(ARBITRUMSEPOLIA_GUARDIAN), + ...getPoolRegistryRevokePermissions(ARBITRUMSEPOLIA_POOL_REGISTRY, ARBITRUMSEPOLIA_GUARDIAN), + ...getComptrollerRevokePermissions(ARBITRUMSEPOLIA_GUARDIAN), + ...getVTokenRevokePermissions(ARBITRUMSEPOLIA_GUARDIAN), + ...getXVSBridgeAdminRevokePermissions(ARBITRUMSEPOLIA_XVS_BRIDGE_ADMIN, ARBITRUMSEPOLIA_GUARDIAN), + ...getRedstoneOracleRevokePermissions(ARBITRUMSEPOLIA_REDSTONE_ORACLE, ARBITRUMSEPOLIA_GUARDIAN), + ...getOmniChainExecutorOwnerRevokePermissions(ARBITRUMSEPOLIA_OMNICHAIN_EXECUTOR_OWNER, ARBITRUMSEPOLIA_GUARDIAN), + ], +}; + +function splitPermissions( + array: ACMCommandsAggregator.PermissionStruct[], + chunkSize: number = 100, +): ACMCommandsAggregator.PermissionStruct[][] { + const result: ACMCommandsAggregator.PermissionStruct[][] = []; + + for (let i = 0; i < array.length; i += chunkSize) { + const chunk = array.slice(i, i + chunkSize); + result.push(chunk); + } + + return result; +} + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const acmCommandsAggregator: ACMCommandsAggregator = await ethers.getContract("ACMCommandsAggregator"); + const networkGrantPermissions = grantPermissions[hre.network.name]; + + for (const permission of networkGrantPermissions) { + if (Object.values(AccountType).includes(permission[2] as AccountType)) { + const timelock = await ethers.getContract(permission[2]); + permission[2] = timelock.address; + } + } + + const _grantPermissions: ACMCommandsAggregator.PermissionStruct[] = networkGrantPermissions.map(permission => ({ + contractAddress: permission[0], + functionSig: permission[1], + account: permission[2], + })); + + const grantChunks = splitPermissions(_grantPermissions); + const grantIndexes: string[] = []; + + for (const chunk of grantChunks) { + const tx = await acmCommandsAggregator.addGrantPermissions(chunk); + + const receipt = await tx.wait(); + const events = receipt.events?.filter(event => event.event === "GrantPermissionsAdded"); + grantIndexes.push(events?.[0].args?.index.toString()); + } + + console.log("Grant Permissions added with indexes: ", grantIndexes.toString()); + + const networkRevokePermissions = revokePermissions[hre.network.name]; + + for (const permission of networkRevokePermissions) { + if (Object.values(AccountType).includes(permission[2] as AccountType)) { + const timelock = await ethers.getContract(permission[2]); + permission[2] = timelock.address; + } + } + + const _revokePermissions: ACMCommandsAggregator.PermissionStruct[] = networkRevokePermissions.map(permission => ({ + contractAddress: permission[0], + functionSig: permission[1], + account: permission[2], + })); + + const revokeChunks = splitPermissions(_revokePermissions); + const revokeIndexes: string[] = []; + + for (const chunk of revokeChunks) { + const tx = await acmCommandsAggregator.addRevokePermissions(chunk); + + const receipt = await tx.wait(); + const events = receipt.events?.filter(event => event.event === "RevokePermissionsAdded"); + revokeIndexes.push(events?.[0].args?.index.toString()); + } + + console.log("Revoke Permissions added with indexes: ", revokeIndexes.toString()); +}; + +func.tags = ["ACMCommandsAggregatorConfigure"]; + +func.skip = async (hre: HardhatRuntimeEnvironment) => + Object.keys(grantPermissions).concat(Object.keys(revokePermissions)).indexOf(hre.network.name) === -1; +export default func; diff --git a/deployments/arbitrumsepolia.json b/deployments/arbitrumsepolia.json index 10b316e1..5ff94943 100644 --- a/deployments/arbitrumsepolia.json +++ b/deployments/arbitrumsepolia.json @@ -2,6 +2,251 @@ "name": "arbitrumsepolia", "chainId": "421614", "contracts": { + "ACMCommandsAggregator": { + "address": "0x4fCbfE445396f31005b3Fd2F6DE2A986d6E2dCB5", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "_acm", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantPermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "revokePermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + }, "AccessControlManager": { "address": "0xa36AD96441cB931D8dFEAAaC97D3FaB4B39E590F", "abi": [ diff --git a/deployments/arbitrumsepolia/ACMCommandsAggregator.json b/deployments/arbitrumsepolia/ACMCommandsAggregator.json new file mode 100644 index 00000000..3e9abd26 --- /dev/null +++ b/deployments/arbitrumsepolia/ACMCommandsAggregator.json @@ -0,0 +1,366 @@ +{ + "address": "0x4fCbfE445396f31005b3Fd2F6DE2A986d6E2dCB5", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "_acm", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantPermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "revokePermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0xd08d840f8b2ba4c8b995af8fa8590dbe3a8b3fda2a5a6c9c656d57d72943333b", + "receipt": { + "to": null, + "from": "0x464779C41C5f1Be598853C1F87bCC7087Ea75f28", + "contractAddress": "0x4fCbfE445396f31005b3Fd2F6DE2A986d6E2dCB5", + "transactionIndex": 1, + "gasUsed": "2940222", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xe6e458a8456e2c01697d9c214317a95a95f83087798cf17181a70806df58d148", + "transactionHash": "0xd08d840f8b2ba4c8b995af8fa8590dbe3a8b3fda2a5a6c9c656d57d72943333b", + "logs": [], + "blockNumber": 85768250, + "cumulativeGasUsed": "2940222", + "status": 1, + "byzantium": true + }, + "args": ["0xa36AD96441cB931D8dFEAAaC97D3FaB4B39E590F"], + "numDeployments": 1, + "solcInputHash": "8462bae4a0ff7e7203ecab090cdf091c", + "metadata": "{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IAccessControlManagerV8\",\"name\":\"_acm\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPermissions\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"GrantPermissionsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"GrantPermissionsExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"RevokePermissionsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"RevokePermissionsExecuted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ACM\",\"outputs\":[{\"internalType\":\"contract IAccessControlManagerV8\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"internalType\":\"struct ACMCommandsAggregator.Permission[]\",\"name\":\"_permissions\",\"type\":\"tuple[]\"}],\"name\":\"addGrantPermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"internalType\":\"struct ACMCommandsAggregator.Permission[]\",\"name\":\"_permissions\",\"type\":\"tuple[]\"}],\"name\":\"addRevokePermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"executeGrantPermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"executeRevokePermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"grantPermissions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"revokePermissions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Venus\",\"kind\":\"dev\",\"methods\":{},\"title\":\"ACMCommandsAggregator\",\"version\":1},\"userdoc\":{\"errors\":{\"ZeroAddressNotAllowed()\":[{\"notice\":\"Thrown if the supplied address is a zero address where it is not allowed\"}]},\"kind\":\"user\",\"methods\":{\"ACM()\":{\"notice\":\"Access control manager contract\"}},\"notice\":\"This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Utils/ACMCommandsAggregator.sol\":\"ACMCommandsAggregator\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n *\\n * _Available since v3.1._\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@venusprotocol/solidity-utilities/contracts/validators.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\\nerror ZeroAddressNotAllowed();\\n\\n/// @notice Thrown if the supplied value is 0 where it is not allowed\\nerror ZeroValueNotAllowed();\\n\\n/// @notice Checks if the provided address is nonzero, reverts otherwise\\n/// @param address_ Address to check\\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\\nfunction ensureNonzeroAddress(address address_) pure {\\n if (address_ == address(0)) {\\n revert ZeroAddressNotAllowed();\\n }\\n}\\n\\n/// @notice Checks if the provided value is nonzero, reverts otherwise\\n/// @param value_ Value to check\\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\\nfunction ensureNonzeroValue(uint256 value_) pure {\\n if (value_ == 0) {\\n revert ZeroValueNotAllowed();\\n }\\n}\\n\",\"keccak256\":\"0xdb88e14d50dd21889ca3329d755673d022c47e8da005b6a545c7f69c2c4b7b86\",\"license\":\"BSD-3-Clause\"},\"contracts/Governance/IAccessControlManagerV8.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\nimport \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\n\\n/**\\n * @title IAccessControlManagerV8\\n * @author Venus\\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\\n */\\ninterface IAccessControlManagerV8 is IAccessControl {\\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\\n\\n function revokeCallPermission(\\n address contractAddress,\\n string calldata functionSig,\\n address accountToRevoke\\n ) external;\\n\\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\\n\\n function hasPermission(\\n address account,\\n address contractAddress,\\n string calldata functionSig\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xaa29b098440d0b3a131c5ecdf25ce548790c1b5ac7bf9b5c0264b6af6f7a1e0b\",\"license\":\"BSD-3-Clause\"},\"contracts/Utils/ACMCommandsAggregator.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\nimport { IAccessControlManagerV8 } from \\\"../Governance/IAccessControlManagerV8.sol\\\";\\nimport { ensureNonzeroAddress } from \\\"@venusprotocol/solidity-utilities/contracts/validators.sol\\\";\\n\\n/**\\n * @title ACMCommandsAggregator\\n * @author Venus\\n * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\\n */\\ncontract ACMCommandsAggregator {\\n /*\\n * @notice Struct to store permission details\\n */\\n struct Permission {\\n /*\\n * @notice Address of the contract\\n */\\n address contractAddress;\\n /*\\n * @notice Function signature\\n */\\n string functionSig;\\n /*\\n * @notice Address of the account\\n */\\n address account;\\n }\\n\\n /**\\n * @notice Access control manager contract\\n */\\n IAccessControlManagerV8 public immutable ACM;\\n\\n /*\\n * @notice 2D array to store grant permissions in batches\\n */\\n Permission[][] public grantPermissions;\\n\\n /*\\n * @notice 2D array to store revoke permissions in batches\\n */\\n Permission[][] public revokePermissions;\\n\\n /*\\n * @notice Event emitted when grant permissions are added\\n */\\n event GrantPermissionsAdded(uint256 index);\\n\\n /*\\n * @notice Event emitted when revoke permissions are added\\n */\\n event RevokePermissionsAdded(uint256 index);\\n\\n /*\\n * @notice Event emitted when grant permissions are executed\\n */\\n event GrantPermissionsExecuted(uint256 index);\\n\\n /*\\n * @notice Event emitted when revoke permissions are executed\\n */\\n event RevokePermissionsExecuted(uint256 index);\\n\\n /*\\n * @notice Error to be thrown when permissions are empty\\n */\\n error EmptyPermissions();\\n\\n /*\\n * @notice Constructor to set the access control manager\\n * @param _acm Address of the access control manager\\n */\\n constructor(IAccessControlManagerV8 _acm) {\\n ensureNonzeroAddress(address(_acm));\\n ACM = _acm;\\n }\\n\\n /*\\n * @notice Function to add grant permissions\\n * @param _permissions Array of permissions\\n * @custom:event Emits GrantPermissionsAdded event\\n */\\n function addGrantPermissions(Permission[] memory _permissions) external {\\n if (_permissions.length == 0) {\\n revert EmptyPermissions();\\n }\\n\\n uint256 index = grantPermissions.length;\\n grantPermissions.push();\\n\\n for (uint256 i; i < _permissions.length; ++i) {\\n grantPermissions[index].push(\\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\\n );\\n }\\n\\n emit GrantPermissionsAdded(index);\\n }\\n\\n /*\\n * @notice Function to add revoke permissions\\n * @param _permissions Array of permissions\\n * @custom:event Emits RevokePermissionsAdded event\\n */\\n function addRevokePermissions(Permission[] memory _permissions) external {\\n if (_permissions.length == 0) {\\n revert EmptyPermissions();\\n }\\n\\n uint256 index = revokePermissions.length;\\n revokePermissions.push();\\n\\n for (uint256 i; i < _permissions.length; ++i) {\\n revokePermissions[index].push(\\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\\n );\\n }\\n\\n emit RevokePermissionsAdded(index);\\n }\\n\\n /*\\n * @notice Function to execute grant permissions\\n * @param index Index of the permissions array\\n * @custom:event Emits GrantPermissionsExecuted event\\n */\\n function executeGrantPermissions(uint256 index) external {\\n uint256 length = grantPermissions[index].length;\\n for (uint256 i; i < length; ++i) {\\n Permission memory permission = grantPermissions[index][i];\\n ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account);\\n }\\n\\n emit GrantPermissionsExecuted(index);\\n }\\n\\n /*\\n * @notice Function to execute revoke permissions\\n * @param index Index of the permissions array\\n * @custom:event Emits RevokePermissionsExecuted event\\n */\\n function executeRevokePermissions(uint256 index) external {\\n uint256 length = revokePermissions[index].length;\\n for (uint256 i; i < length; ++i) {\\n Permission memory permission = revokePermissions[index][i];\\n ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account);\\n }\\n\\n emit RevokePermissionsExecuted(index);\\n }\\n}\\n\",\"keccak256\":\"0xe642b8f0e0fedc74d31196197bc7d78b43b44eab556c07ec74d6b75ccf8d0f8c\",\"license\":\"BSD-3-Clause\"}},\"version\":1}", + "bytecode": "0x60a0604052348015600f57600080fd5b506040516110c73803806110c7833981016040819052602c91606c565b6033816043565b6001600160a01b0316608052609a565b6001600160a01b0381166069576040516342bcdf7f60e11b815260040160405180910390fd5b50565b600060208284031215607d57600080fd5b81516001600160a01b0381168114609357600080fd5b9392505050565b6080516110046100c360003960008181610100015281816102de0152610a0101526110046000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80639d6c76b81161005b5780639d6c76b8146100d5578063de46a235146100e8578063f9b80da1146100fb578063ff1575e11461014757600080fd5b806322473d8c14610082578063514aab87146100975780635666a5ea146100c2575b600080fd5b610095610090366004610ab8565b61015a565b005b6100aa6100a5366004610ad1565b61038d565b6040516100b993929190610af3565b60405180910390f35b6100956100d0366004610c59565b610492565b6100956100e3366004610c59565b610689565b6100956100f6366004610ab8565b61087f565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b9565b6100aa610155366004610ad1565b610aa8565b60006001828154811061016f5761016f610de1565b600091825260208220015491505b818110156103545760006001848154811061019a5761019a610de1565b9060005260206000200182815481106101b5576101b5610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161020290610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461022e90610e10565b801561027b5780601f106102505761010080835404028352916020019161027b565b820191906000526020600020905b81548152906001019060200180831161025e57829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f545f7a320000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363545f7a329361031693909291600401610af3565b600060405180830381600087803b15801561033057600080fd5b505af1158015610344573d6000803e3d6000fd5b505050505080600101905061017d565b506040518281527f1382323d6618527d8b03daa05db815f0490966e8b80679fe5ad3d868f84e1a71906020015b60405180910390a15050565b6000828154811061039d57600080fd5b9060005260206000200181815481106103b557600080fd5b60009182526020909120600390910201805460018201805473ffffffffffffffffffffffffffffffffffffffff90921694509192506103f390610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461041f90610e10565b801561046c5780601f106104415761010080835404028352916020019161046c565b820191906000526020600020905b81548152906001019060200180831161044f57829003601f168201915b5050506002909301549192505073ffffffffffffffffffffffffffffffffffffffff1683565b80516000036104cd576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805480820182556000918252905b825181101561065857600182815481106104f9576104f9610de1565b90600052602060002001604051806060016040528085848151811061052057610520610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061055957610559610de1565b602002602001015160200151815260200185848151811061057c5761057c610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906106019082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016104dd565b506040518181527f75922591bf2cec980645dc4a32bb7d5e8da9a15fda86dacf06f8402cecd1478f90602001610381565b80516000036106c4576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054600181018255818052905b825181101561084e57600082815481106106ef576106ef610de1565b90600052602060002001604051806060016040528085848151811061071657610716610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061074f5761074f610de1565b602002602001015160200151815260200185848151811061077257610772610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906107f79082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016106d3565b506040518181527ff8ca6ea7cc31be8572501c37ef5e9e8298be717fb881e0b1ca785aecc4d25e9f90602001610381565b600080828154811061089357610893610de1565b600091825260208220015491505b81811015610a775760008084815481106108bd576108bd610de1565b9060005260206000200182815481106108d8576108d8610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161092590610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461095190610e10565b801561099e5780601f106109735761010080835404028352916020019161099e565b820191906000526020600020905b81548152906001019060200180831161098157829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f584f6b600000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363584f6b6093610a3993909291600401610af3565b600060405180830381600087803b158015610a5357600080fd5b505af1158015610a67573d6000803e3d6000fd5b50505050508060010190506108a1565b506040518281527f01a805f459381af632ecab72ec192c3f9a4c72d26be089026ffd6636d82de98890602001610381565b6001828154811061039d57600080fd5b600060208284031215610aca57600080fd5b5035919050565b60008060408385031215610ae457600080fd5b50508035926020909101359150565b600073ffffffffffffffffffffffffffffffffffffffff8086168352602060606020850152855180606086015260005b81811015610b3f57878101830151868201608001528201610b23565b5060006080828701015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010193505050808416604084015250949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610bdb57610bdb610b89565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c2857610c28610b89565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c5457600080fd5b919050565b60006020808385031215610c6c57600080fd5b823567ffffffffffffffff80821115610c8457600080fd5b818501915085601f830112610c9857600080fd5b813581811115610caa57610caa610b89565b8060051b610cb9858201610be1565b9182528381018501918581019089841115610cd357600080fd5b86860192505b83831015610dd457823585811115610cf057600080fd5b86017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06060828d0382011215610d265760008081fd5b610d2e610bb8565b610d398a8401610c30565b815260408084013589811115610d4f5760008081fd5b8401603f81018f13610d615760008081fd5b8b8101358a811115610d7557610d75610b89565b610d858d86601f84011601610be1565b94508085528f83828401011115610d9c5760008081fd5b808383018e87013760008d82870101525050828b830152610dbf60608501610c30565b90820152845250509186019190860190610cd9565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c90821680610e2457607f821691505b602082108103610e5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610eaf576000816000526020600020601f850160051c81016020861015610e8c5750805b601f850160051c820191505b81811015610eab57828155600101610e98565b5050505b505050565b815167ffffffffffffffff811115610ece57610ece610b89565b610ee281610edc8454610e10565b84610e63565b602080601f831160018114610f355760008415610eff5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610eab565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610f8257888601518255948401946001909101908401610f63565b5085821015610fbe57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122090d4936e163063dfe747da5bf04cc06002b17436a13e78a30b2797e6219ebb2264736f6c63430008190033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80639d6c76b81161005b5780639d6c76b8146100d5578063de46a235146100e8578063f9b80da1146100fb578063ff1575e11461014757600080fd5b806322473d8c14610082578063514aab87146100975780635666a5ea146100c2575b600080fd5b610095610090366004610ab8565b61015a565b005b6100aa6100a5366004610ad1565b61038d565b6040516100b993929190610af3565b60405180910390f35b6100956100d0366004610c59565b610492565b6100956100e3366004610c59565b610689565b6100956100f6366004610ab8565b61087f565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b9565b6100aa610155366004610ad1565b610aa8565b60006001828154811061016f5761016f610de1565b600091825260208220015491505b818110156103545760006001848154811061019a5761019a610de1565b9060005260206000200182815481106101b5576101b5610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161020290610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461022e90610e10565b801561027b5780601f106102505761010080835404028352916020019161027b565b820191906000526020600020905b81548152906001019060200180831161025e57829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f545f7a320000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363545f7a329361031693909291600401610af3565b600060405180830381600087803b15801561033057600080fd5b505af1158015610344573d6000803e3d6000fd5b505050505080600101905061017d565b506040518281527f1382323d6618527d8b03daa05db815f0490966e8b80679fe5ad3d868f84e1a71906020015b60405180910390a15050565b6000828154811061039d57600080fd5b9060005260206000200181815481106103b557600080fd5b60009182526020909120600390910201805460018201805473ffffffffffffffffffffffffffffffffffffffff90921694509192506103f390610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461041f90610e10565b801561046c5780601f106104415761010080835404028352916020019161046c565b820191906000526020600020905b81548152906001019060200180831161044f57829003601f168201915b5050506002909301549192505073ffffffffffffffffffffffffffffffffffffffff1683565b80516000036104cd576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805480820182556000918252905b825181101561065857600182815481106104f9576104f9610de1565b90600052602060002001604051806060016040528085848151811061052057610520610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061055957610559610de1565b602002602001015160200151815260200185848151811061057c5761057c610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906106019082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016104dd565b506040518181527f75922591bf2cec980645dc4a32bb7d5e8da9a15fda86dacf06f8402cecd1478f90602001610381565b80516000036106c4576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054600181018255818052905b825181101561084e57600082815481106106ef576106ef610de1565b90600052602060002001604051806060016040528085848151811061071657610716610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061074f5761074f610de1565b602002602001015160200151815260200185848151811061077257610772610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906107f79082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016106d3565b506040518181527ff8ca6ea7cc31be8572501c37ef5e9e8298be717fb881e0b1ca785aecc4d25e9f90602001610381565b600080828154811061089357610893610de1565b600091825260208220015491505b81811015610a775760008084815481106108bd576108bd610de1565b9060005260206000200182815481106108d8576108d8610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161092590610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461095190610e10565b801561099e5780601f106109735761010080835404028352916020019161099e565b820191906000526020600020905b81548152906001019060200180831161098157829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f584f6b600000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363584f6b6093610a3993909291600401610af3565b600060405180830381600087803b158015610a5357600080fd5b505af1158015610a67573d6000803e3d6000fd5b50505050508060010190506108a1565b506040518281527f01a805f459381af632ecab72ec192c3f9a4c72d26be089026ffd6636d82de98890602001610381565b6001828154811061039d57600080fd5b600060208284031215610aca57600080fd5b5035919050565b60008060408385031215610ae457600080fd5b50508035926020909101359150565b600073ffffffffffffffffffffffffffffffffffffffff8086168352602060606020850152855180606086015260005b81811015610b3f57878101830151868201608001528201610b23565b5060006080828701015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010193505050808416604084015250949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610bdb57610bdb610b89565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c2857610c28610b89565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c5457600080fd5b919050565b60006020808385031215610c6c57600080fd5b823567ffffffffffffffff80821115610c8457600080fd5b818501915085601f830112610c9857600080fd5b813581811115610caa57610caa610b89565b8060051b610cb9858201610be1565b9182528381018501918581019089841115610cd357600080fd5b86860192505b83831015610dd457823585811115610cf057600080fd5b86017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06060828d0382011215610d265760008081fd5b610d2e610bb8565b610d398a8401610c30565b815260408084013589811115610d4f5760008081fd5b8401603f81018f13610d615760008081fd5b8b8101358a811115610d7557610d75610b89565b610d858d86601f84011601610be1565b94508085528f83828401011115610d9c5760008081fd5b808383018e87013760008d82870101525050828b830152610dbf60608501610c30565b90820152845250509186019190860190610cd9565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c90821680610e2457607f821691505b602082108103610e5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610eaf576000816000526020600020601f850160051c81016020861015610e8c5750805b601f850160051c820191505b81811015610eab57828155600101610e98565b5050505b505050565b815167ffffffffffffffff811115610ece57610ece610b89565b610ee281610edc8454610e10565b84610e63565b602080601f831160018114610f355760008415610eff5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610eab565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610f8257888601518255948401946001909101908401610f63565b5085821015610fbe57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122090d4936e163063dfe747da5bf04cc06002b17436a13e78a30b2797e6219ebb2264736f6c63430008190033", + "devdoc": { + "author": "Venus", + "kind": "dev", + "methods": {}, + "title": "ACMCommandsAggregator", + "version": 1 + }, + "userdoc": { + "errors": { + "ZeroAddressNotAllowed()": [ + { + "notice": "Thrown if the supplied address is a zero address where it is not allowed" + } + ] + }, + "kind": "user", + "methods": { + "ACM()": { + "notice": "Access control manager contract" + } + }, + "notice": "This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 8955, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "grantPermissions", + "offset": 0, + "slot": "0", + "type": "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage" + }, + { + "astId": 8960, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "revokePermissions", + "offset": 0, + "slot": "1", + "type": "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage": { + "base": "t_array(t_struct(Permission)8946_storage)dyn_storage", + "encoding": "dynamic_array", + "label": "struct ACMCommandsAggregator.Permission[][]", + "numberOfBytes": "32" + }, + "t_array(t_struct(Permission)8946_storage)dyn_storage": { + "base": "t_struct(Permission)8946_storage", + "encoding": "dynamic_array", + "label": "struct ACMCommandsAggregator.Permission[]", + "numberOfBytes": "32" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Permission)8946_storage": { + "encoding": "inplace", + "label": "struct ACMCommandsAggregator.Permission", + "members": [ + { + "astId": 8941, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "contractAddress", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 8943, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "functionSig", + "offset": 0, + "slot": "1", + "type": "t_string_storage" + }, + { + "astId": 8945, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "account", + "offset": 0, + "slot": "2", + "type": "t_address" + } + ], + "numberOfBytes": "96" + } + } + } +} diff --git a/deployments/arbitrumsepolia/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json b/deployments/arbitrumsepolia/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json new file mode 100644 index 00000000..12855c7e --- /dev/null +++ b/deployments/arbitrumsepolia/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json @@ -0,0 +1,151 @@ +{ + "language": "Solidity", + "sources": { + "@layerzerolabs/solidity-examples/contracts/libraries/BytesLib.sol": { + "content": "// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\nlibrary BytesLib {\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(\n 0x40,\n and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n )\n )\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask)))\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(\n bytes memory _bytes,\n uint _start,\n uint _length\n ) internal pure returns (bytes memory) {\n require(_length + 31 >= _length, \"slice_overflow\");\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint _start) internal pure returns (uint) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n } eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for {\n\n } eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/libraries/ExcessivelySafeCall.sol": { + "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.7.6;\n\nlibrary ExcessivelySafeCall {\n uint constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(\n address _target,\n uint _gas,\n uint16 _maxCopy,\n bytes memory _calldata\n ) internal returns (bool, bytes memory) {\n // set up for assembly call\n uint _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly {\n _success := call(\n _gas, // gas\n _target, // recipient\n 0, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) {\n _toCopy := _maxCopy\n }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(\n address _target,\n uint _gas,\n uint16 _maxCopy,\n bytes memory _calldata\n ) internal view returns (bool, bytes memory) {\n // set up for assembly call\n uint _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly {\n _success := staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) {\n _toCopy := _maxCopy\n }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /**\n * @notice Swaps function selectors in encoded contract calls\n * @dev Allows reuse of encoded calldata for functions with identical\n * argument types but different names. It simply swaps out the first 4 bytes\n * for the new selector. This function modifies memory in place, and should\n * only be used with caution.\n * @param _newSelector The new 4-byte selector\n * @param _buf The encoded contract args\n */\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint _mask = LOW_28_MASK;\n assembly {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\n\ninterface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {\n // @notice send a LayerZero message to the specified address at a LayerZero endpoint.\n // @param _dstChainId - the destination chain identifier\n // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains\n // @param _payload - a custom bytes payload to send to the destination contract\n // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address\n // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction\n // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination\n function send(\n uint16 _dstChainId,\n bytes calldata _destination,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes calldata _adapterParams\n ) external payable;\n\n // @notice used by the messaging library to publish verified payload\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source contract (as bytes) at the source chain\n // @param _dstAddress - the address on destination chain\n // @param _nonce - the unbound message ordering nonce\n // @param _gasLimit - the gas limit for external contract execution\n // @param _payload - verified payload to send to the destination contract\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n address _dstAddress,\n uint64 _nonce,\n uint _gasLimit,\n bytes calldata _payload\n ) external;\n\n // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);\n\n // @notice get the outboundNonce from this source chain which, consequently, is always an EVM\n // @param _srcAddress - the source chain contract address\n function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);\n\n // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery\n // @param _dstChainId - the destination chain identifier\n // @param _userApplication - the user app address on this EVM chain\n // @param _payload - the custom message to send over LayerZero\n // @param _payInZRO - if false, user app pays the protocol fee in native token\n // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes calldata _payload,\n bool _payInZRO,\n bytes calldata _adapterParam\n ) external view returns (uint nativeFee, uint zroFee);\n\n // @notice get this Endpoint's immutable source identifier\n function getChainId() external view returns (uint16);\n\n // @notice the interface to retry failed message on this Endpoint destination\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n // @param _payload - the payload to be retried\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n bytes calldata _payload\n ) external;\n\n // @notice query if any STORED payload (message blocking) at the endpoint.\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);\n\n // @notice query if the _libraryAddress is valid for sending msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getSendLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the _libraryAddress is valid for receiving msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getReceiveLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the non-reentrancy guard for send() is on\n // @return true if the guard is on. false otherwise\n function isSendingPayload() external view returns (bool);\n\n // @notice query if the non-reentrancy guard for receive() is on\n // @return true if the guard is on. false otherwise\n function isReceivingPayload() external view returns (bool);\n\n // @notice get the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _userApplication - the contract address of the user application\n // @param _configType - type of configuration. every messaging library has its own convention.\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address _userApplication,\n uint _configType\n ) external view returns (bytes memory);\n\n // @notice get the send() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getSendVersion(address _userApplication) external view returns (uint16);\n\n // @notice get the lzReceive() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getReceiveVersion(address _userApplication) external view returns (uint16);\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroReceiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroReceiver {\n // @notice LayerZero endpoint will invoke this function to deliver the message on the destination\n // @param _srcChainId - the source endpoint identifier\n // @param _srcAddress - the source sending contract address from the source chain\n // @param _nonce - the ordered message nonce\n // @param _payload - the signed payload is the UA bytes has encoded to be sent\n function lzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) external;\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroUserApplicationConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroUserApplicationConfig {\n // @notice set the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _configType - type of configuration. every messaging library has its own convention.\n // @param _config - configuration in the bytes. can encode arbitrary content.\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint _configType,\n bytes calldata _config\n ) external;\n\n // @notice set the send() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setSendVersion(uint16 _version) external;\n\n // @notice set the lzReceive() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setReceiveVersion(uint16 _version) external;\n\n // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload\n // @param _srcChainId - the chainId of the source chain\n // @param _srcAddress - the contract address of the source contract at the source chain\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/libs/LzLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.6.0;\npragma experimental ABIEncoderV2;\n\nlibrary LzLib {\n // LayerZero communication\n struct CallParams {\n address payable refundAddress;\n address zroPaymentAddress;\n }\n\n //---------------------------------------------------------------------------\n // Address type handling\n\n struct AirdropParams {\n uint airdropAmount;\n bytes32 airdropAddress;\n }\n\n function buildAdapterParams(LzLib.AirdropParams memory _airdropParams, uint _uaGasLimit) internal pure returns (bytes memory adapterParams) {\n if (_airdropParams.airdropAmount == 0 && _airdropParams.airdropAddress == bytes32(0x0)) {\n adapterParams = buildDefaultAdapterParams(_uaGasLimit);\n } else {\n adapterParams = buildAirdropAdapterParams(_uaGasLimit, _airdropParams);\n }\n }\n\n // Build Adapter Params\n function buildDefaultAdapterParams(uint _uaGas) internal pure returns (bytes memory) {\n // txType 1\n // bytes [2 32 ]\n // fields [txType extraGas]\n return abi.encodePacked(uint16(1), _uaGas);\n }\n\n function buildAirdropAdapterParams(uint _uaGas, AirdropParams memory _params) internal pure returns (bytes memory) {\n require(_params.airdropAmount > 0, \"Airdrop amount must be greater than 0\");\n require(_params.airdropAddress != bytes32(0x0), \"Airdrop address must be set\");\n\n // txType 2\n // bytes [2 32 32 bytes[] ]\n // fields [txType extraGas dstNativeAmt dstNativeAddress]\n return abi.encodePacked(uint16(2), _uaGas, _params.airdropAmount, _params.airdropAddress);\n }\n\n function getGasLimit(bytes memory _adapterParams) internal pure returns (uint gasLimit) {\n require(_adapterParams.length == 34 || _adapterParams.length > 66, \"Invalid adapterParams\");\n assembly {\n gasLimit := mload(add(_adapterParams, 34))\n }\n }\n\n // Decode Adapter Params\n function decodeAdapterParams(bytes memory _adapterParams)\n internal\n pure\n returns (\n uint16 txType,\n uint uaGas,\n uint airdropAmount,\n address payable airdropAddress\n )\n {\n require(_adapterParams.length == 34 || _adapterParams.length > 66, \"Invalid adapterParams\");\n assembly {\n txType := mload(add(_adapterParams, 2))\n uaGas := mload(add(_adapterParams, 34))\n }\n require(txType == 1 || txType == 2, \"Unsupported txType\");\n require(uaGas > 0, \"Gas too low\");\n\n if (txType == 2) {\n assembly {\n airdropAmount := mload(add(_adapterParams, 66))\n airdropAddress := mload(add(_adapterParams, 86))\n }\n }\n }\n\n //---------------------------------------------------------------------------\n // Address type handling\n function bytes32ToAddress(bytes32 _bytes32Address) internal pure returns (address _address) {\n return address(uint160(uint(_bytes32Address)));\n }\n\n function addressToBytes32(address _address) internal pure returns (bytes32 _bytes32Address) {\n return bytes32(uint(uint160(_address)));\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/LzApp.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./interfaces/ILayerZeroReceiver.sol\";\nimport \"./interfaces/ILayerZeroUserApplicationConfig.sol\";\nimport \"./interfaces/ILayerZeroEndpoint.sol\";\nimport \"../libraries/BytesLib.sol\";\n\n/*\n * a generic LzReceiver implementation\n */\nabstract contract LzApp is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {\n using BytesLib for bytes;\n\n // ua can not send payload larger than this by default, but it can be changed by the ua owner\n uint public constant DEFAULT_PAYLOAD_SIZE_LIMIT = 10000;\n\n ILayerZeroEndpoint public immutable lzEndpoint;\n mapping(uint16 => bytes) public trustedRemoteLookup;\n mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;\n mapping(uint16 => uint) public payloadSizeLimitLookup;\n address public precrime;\n\n event SetPrecrime(address precrime);\n event SetTrustedRemote(uint16 _remoteChainId, bytes _path);\n event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);\n event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);\n\n constructor(address _endpoint) {\n lzEndpoint = ILayerZeroEndpoint(_endpoint);\n }\n\n function lzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public virtual override {\n // lzReceive must be called by the endpoint for security\n require(_msgSender() == address(lzEndpoint), \"LzApp: invalid endpoint caller\");\n\n bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];\n // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.\n require(\n _srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote),\n \"LzApp: invalid source sending contract\"\n );\n\n _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging\n function _blockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual;\n\n function _lzSend(\n uint16 _dstChainId,\n bytes memory _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams,\n uint _nativeFee\n ) internal virtual {\n bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];\n require(trustedRemote.length != 0, \"LzApp: destination chain is not a trusted source\");\n _checkPayloadSize(_dstChainId, _payload.length);\n lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);\n }\n\n function _checkGasLimit(\n uint16 _dstChainId,\n uint16 _type,\n bytes memory _adapterParams,\n uint _extraGas\n ) internal view virtual {\n uint providedGasLimit = _getGasLimit(_adapterParams);\n uint minGasLimit = minDstGasLookup[_dstChainId][_type];\n require(minGasLimit > 0, \"LzApp: minGasLimit not set\");\n require(providedGasLimit >= minGasLimit + _extraGas, \"LzApp: gas limit is too low\");\n }\n\n function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {\n require(_adapterParams.length >= 34, \"LzApp: invalid adapterParams\");\n assembly {\n gasLimit := mload(add(_adapterParams, 34))\n }\n }\n\n function _checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internal view virtual {\n uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId];\n if (payloadSizeLimit == 0) {\n // use default if not set\n payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;\n }\n require(_payloadSize <= payloadSizeLimit, \"LzApp: payload size is too large\");\n }\n\n //---------------------------UserApplication config----------------------------------------\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address,\n uint _configType\n ) external view returns (bytes memory) {\n return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);\n }\n\n // generic config for LayerZero user Application\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint _configType,\n bytes calldata _config\n ) external override onlyOwner {\n lzEndpoint.setConfig(_version, _chainId, _configType, _config);\n }\n\n function setSendVersion(uint16 _version) external override onlyOwner {\n lzEndpoint.setSendVersion(_version);\n }\n\n function setReceiveVersion(uint16 _version) external override onlyOwner {\n lzEndpoint.setReceiveVersion(_version);\n }\n\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {\n lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);\n }\n\n // _path = abi.encodePacked(remoteAddress, localAddress)\n // this function set the trusted path for the cross-chain communication\n function setTrustedRemote(uint16 _remoteChainId, bytes calldata _path) external onlyOwner {\n trustedRemoteLookup[_remoteChainId] = _path;\n emit SetTrustedRemote(_remoteChainId, _path);\n }\n\n function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external onlyOwner {\n trustedRemoteLookup[_remoteChainId] = abi.encodePacked(_remoteAddress, address(this));\n emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);\n }\n\n function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) {\n bytes memory path = trustedRemoteLookup[_remoteChainId];\n require(path.length != 0, \"LzApp: no trusted path record\");\n return path.slice(0, path.length - 20); // the last 20 bytes should be address(this)\n }\n\n function setPrecrime(address _precrime) external onlyOwner {\n precrime = _precrime;\n emit SetPrecrime(_precrime);\n }\n\n function setMinDstGas(\n uint16 _dstChainId,\n uint16 _packetType,\n uint _minGas\n ) external onlyOwner {\n minDstGasLookup[_dstChainId][_packetType] = _minGas;\n emit SetMinDstGas(_dstChainId, _packetType, _minGas);\n }\n\n // if the size is 0, it means default size limit\n function setPayloadSizeLimit(uint16 _dstChainId, uint _size) external onlyOwner {\n payloadSizeLimitLookup[_dstChainId] = _size;\n }\n\n //--------------------------- VIEW FUNCTION ----------------------------------------\n function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {\n bytes memory trustedSource = trustedRemoteLookup[_srcChainId];\n return keccak256(trustedSource) == keccak256(_srcAddress);\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/mocks/LZEndpointMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\npragma abicoder v2;\n\nimport \"../interfaces/ILayerZeroReceiver.sol\";\nimport \"../interfaces/ILayerZeroEndpoint.sol\";\nimport \"../libs/LzLib.sol\";\n\n/*\nlike a real LayerZero endpoint but can be mocked, which handle message transmission, verification, and receipt.\n- blocking: LayerZero provides ordered delivery of messages from a given sender to a destination chain.\n- non-reentrancy: endpoint has a non-reentrancy guard for both the send() and receive(), respectively.\n- adapter parameters: allows UAs to add arbitrary transaction params in the send() function, like airdrop on destination chain.\nunlike a real LayerZero endpoint, it is\n- no messaging library versioning\n- send() will short circuit to lzReceive()\n- no user application configuration\n*/\ncontract LZEndpointMock is ILayerZeroEndpoint {\n uint8 internal constant _NOT_ENTERED = 1;\n uint8 internal constant _ENTERED = 2;\n\n mapping(address => address) public lzEndpointLookup;\n\n uint16 public mockChainId;\n bool public nextMsgBlocked;\n\n // fee config\n RelayerFeeConfig public relayerFeeConfig;\n ProtocolFeeConfig public protocolFeeConfig;\n uint public oracleFee;\n bytes public defaultAdapterParams;\n\n // path = remote addrss + local address\n // inboundNonce = [srcChainId][path].\n mapping(uint16 => mapping(bytes => uint64)) public inboundNonce;\n //todo: this is a hack\n // outboundNonce = [dstChainId][srcAddress]\n mapping(uint16 => mapping(address => uint64)) public outboundNonce;\n // // outboundNonce = [dstChainId][path].\n // mapping(uint16 => mapping(bytes => uint64)) public outboundNonce;\n // storedPayload = [srcChainId][path]\n mapping(uint16 => mapping(bytes => StoredPayload)) public storedPayload;\n // msgToDeliver = [srcChainId][path]\n mapping(uint16 => mapping(bytes => QueuedPayload[])) public msgsToDeliver;\n\n // reentrancy guard\n uint8 internal _send_entered_state = 1;\n uint8 internal _receive_entered_state = 1;\n\n struct ProtocolFeeConfig {\n uint zroFee;\n uint nativeBP;\n }\n\n struct RelayerFeeConfig {\n uint128 dstPriceRatio; // 10^10\n uint128 dstGasPriceInWei;\n uint128 dstNativeAmtCap;\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n struct StoredPayload {\n uint64 payloadLength;\n address dstAddress;\n bytes32 payloadHash;\n }\n\n struct QueuedPayload {\n address dstAddress;\n uint64 nonce;\n bytes payload;\n }\n\n modifier sendNonReentrant() {\n require(_send_entered_state == _NOT_ENTERED, \"LayerZeroMock: no send reentrancy\");\n _send_entered_state = _ENTERED;\n _;\n _send_entered_state = _NOT_ENTERED;\n }\n\n modifier receiveNonReentrant() {\n require(_receive_entered_state == _NOT_ENTERED, \"LayerZeroMock: no receive reentrancy\");\n _receive_entered_state = _ENTERED;\n _;\n _receive_entered_state = _NOT_ENTERED;\n }\n\n event UaForceResumeReceive(uint16 chainId, bytes srcAddress);\n event PayloadCleared(uint16 srcChainId, bytes srcAddress, uint64 nonce, address dstAddress);\n event PayloadStored(uint16 srcChainId, bytes srcAddress, address dstAddress, uint64 nonce, bytes payload, bytes reason);\n event ValueTransferFailed(address indexed to, uint indexed quantity);\n\n constructor(uint16 _chainId) {\n mockChainId = _chainId;\n\n // init config\n relayerFeeConfig = RelayerFeeConfig({\n dstPriceRatio: 1e10, // 1:1, same chain, same native coin\n dstGasPriceInWei: 1e10,\n dstNativeAmtCap: 1e19,\n baseGas: 100,\n gasPerByte: 1\n });\n protocolFeeConfig = ProtocolFeeConfig({zroFee: 1e18, nativeBP: 1000}); // BP 0.1\n oracleFee = 1e16;\n defaultAdapterParams = LzLib.buildDefaultAdapterParams(200000);\n }\n\n // ------------------------------ ILayerZeroEndpoint Functions ------------------------------\n function send(\n uint16 _chainId,\n bytes memory _path,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams\n ) external payable override sendNonReentrant {\n require(_path.length == 40, \"LayerZeroMock: incorrect remote address size\"); // only support evm chains\n\n address dstAddr;\n assembly {\n dstAddr := mload(add(_path, 20))\n }\n\n address lzEndpoint = lzEndpointLookup[dstAddr];\n require(lzEndpoint != address(0), \"LayerZeroMock: destination LayerZero Endpoint not found\");\n\n // not handle zro token\n bytes memory adapterParams = _adapterParams.length > 0 ? _adapterParams : defaultAdapterParams;\n (uint nativeFee, ) = estimateFees(_chainId, msg.sender, _payload, _zroPaymentAddress != address(0x0), adapterParams);\n require(msg.value >= nativeFee, \"LayerZeroMock: not enough native for fees\");\n\n uint64 nonce = ++outboundNonce[_chainId][msg.sender];\n\n // refund if they send too much\n uint amount = msg.value - nativeFee;\n if (amount > 0) {\n (bool success, ) = _refundAddress.call{value: amount}(\"\");\n require(success, \"LayerZeroMock: failed to refund\");\n }\n\n // Mock the process of receiving msg on dst chain\n // Mock the relayer paying the dstNativeAddr the amount of extra native token\n (, uint extraGas, uint dstNativeAmt, address payable dstNativeAddr) = LzLib.decodeAdapterParams(adapterParams);\n if (dstNativeAmt > 0) {\n (bool success, ) = dstNativeAddr.call{value: dstNativeAmt}(\"\");\n if (!success) {\n emit ValueTransferFailed(dstNativeAddr, dstNativeAmt);\n }\n }\n\n bytes memory srcUaAddress = abi.encodePacked(msg.sender, dstAddr); // cast this address to bytes\n bytes memory payload = _payload;\n LZEndpointMock(lzEndpoint).receivePayload(mockChainId, srcUaAddress, dstAddr, nonce, extraGas, payload);\n }\n\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _path,\n address _dstAddress,\n uint64 _nonce,\n uint _gasLimit,\n bytes calldata _payload\n ) external override receiveNonReentrant {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n\n // assert and increment the nonce. no message shuffling\n require(_nonce == ++inboundNonce[_srcChainId][_path], \"LayerZeroMock: wrong nonce\");\n\n // queue the following msgs inside of a stack to simulate a successful send on src, but not fully delivered on dst\n if (sp.payloadHash != bytes32(0)) {\n QueuedPayload[] storage msgs = msgsToDeliver[_srcChainId][_path];\n QueuedPayload memory newMsg = QueuedPayload(_dstAddress, _nonce, _payload);\n\n // warning, might run into gas issues trying to forward through a bunch of queued msgs\n // shift all the msgs over so we can treat this like a fifo via array.pop()\n if (msgs.length > 0) {\n // extend the array\n msgs.push(newMsg);\n\n // shift all the indexes up for pop()\n for (uint i = 0; i < msgs.length - 1; i++) {\n msgs[i + 1] = msgs[i];\n }\n\n // put the newMsg at the bottom of the stack\n msgs[0] = newMsg;\n } else {\n msgs.push(newMsg);\n }\n } else if (nextMsgBlocked) {\n storedPayload[_srcChainId][_path] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));\n emit PayloadStored(_srcChainId, _path, _dstAddress, _nonce, _payload, bytes(\"\"));\n // ensure the next msgs that go through are no longer blocked\n nextMsgBlocked = false;\n } else {\n try ILayerZeroReceiver(_dstAddress).lzReceive{gas: _gasLimit}(_srcChainId, _path, _nonce, _payload) {} catch (bytes memory reason) {\n storedPayload[_srcChainId][_path] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));\n emit PayloadStored(_srcChainId, _path, _dstAddress, _nonce, _payload, reason);\n // ensure the next msgs that go through are no longer blocked\n nextMsgBlocked = false;\n }\n }\n }\n\n function getInboundNonce(uint16 _chainID, bytes calldata _path) external view override returns (uint64) {\n return inboundNonce[_chainID][_path];\n }\n\n function getOutboundNonce(uint16 _chainID, address _srcAddress) external view override returns (uint64) {\n return outboundNonce[_chainID][_srcAddress];\n }\n\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes memory _payload,\n bool _payInZRO,\n bytes memory _adapterParams\n ) public view override returns (uint nativeFee, uint zroFee) {\n bytes memory adapterParams = _adapterParams.length > 0 ? _adapterParams : defaultAdapterParams;\n\n // Relayer Fee\n uint relayerFee = _getRelayerFee(_dstChainId, 1, _userApplication, _payload.length, adapterParams);\n\n // LayerZero Fee\n uint protocolFee = _getProtocolFees(_payInZRO, relayerFee, oracleFee);\n _payInZRO ? zroFee = protocolFee : nativeFee = protocolFee;\n\n // return the sum of fees\n nativeFee = nativeFee + relayerFee + oracleFee;\n }\n\n function getChainId() external view override returns (uint16) {\n return mockChainId;\n }\n\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _path,\n bytes calldata _payload\n ) external override {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n require(sp.payloadHash != bytes32(0), \"LayerZeroMock: no stored payload\");\n require(_payload.length == sp.payloadLength && keccak256(_payload) == sp.payloadHash, \"LayerZeroMock: invalid payload\");\n\n address dstAddress = sp.dstAddress;\n // empty the storedPayload\n sp.payloadLength = 0;\n sp.dstAddress = address(0);\n sp.payloadHash = bytes32(0);\n\n uint64 nonce = inboundNonce[_srcChainId][_path];\n\n ILayerZeroReceiver(dstAddress).lzReceive(_srcChainId, _path, nonce, _payload);\n emit PayloadCleared(_srcChainId, _path, nonce, dstAddress);\n }\n\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _path) external view override returns (bool) {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n return sp.payloadHash != bytes32(0);\n }\n\n function getSendLibraryAddress(address) external view override returns (address) {\n return address(this);\n }\n\n function getReceiveLibraryAddress(address) external view override returns (address) {\n return address(this);\n }\n\n function isSendingPayload() external view override returns (bool) {\n return _send_entered_state == _ENTERED;\n }\n\n function isReceivingPayload() external view override returns (bool) {\n return _receive_entered_state == _ENTERED;\n }\n\n function getConfig(\n uint16, /*_version*/\n uint16, /*_chainId*/\n address, /*_ua*/\n uint /*_configType*/\n ) external pure override returns (bytes memory) {\n return \"\";\n }\n\n function getSendVersion(\n address /*_userApplication*/\n ) external pure override returns (uint16) {\n return 1;\n }\n\n function getReceiveVersion(\n address /*_userApplication*/\n ) external pure override returns (uint16) {\n return 1;\n }\n\n function setConfig(\n uint16, /*_version*/\n uint16, /*_chainId*/\n uint, /*_configType*/\n bytes memory /*_config*/\n ) external override {}\n\n function setSendVersion(\n uint16 /*version*/\n ) external override {}\n\n function setReceiveVersion(\n uint16 /*version*/\n ) external override {}\n\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _path) external override {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n // revert if no messages are cached. safeguard malicious UA behaviour\n require(sp.payloadHash != bytes32(0), \"LayerZeroMock: no stored payload\");\n require(sp.dstAddress == msg.sender, \"LayerZeroMock: invalid caller\");\n\n // empty the storedPayload\n sp.payloadLength = 0;\n sp.dstAddress = address(0);\n sp.payloadHash = bytes32(0);\n\n emit UaForceResumeReceive(_srcChainId, _path);\n\n // resume the receiving of msgs after we force clear the \"stuck\" msg\n _clearMsgQue(_srcChainId, _path);\n }\n\n // ------------------------------ Other Public/External Functions --------------------------------------------------\n\n function getLengthOfQueue(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint) {\n return msgsToDeliver[_srcChainId][_srcAddress].length;\n }\n\n // used to simulate messages received get stored as a payload\n function blockNextMsg() external {\n nextMsgBlocked = true;\n }\n\n function setDestLzEndpoint(address destAddr, address lzEndpointAddr) external {\n lzEndpointLookup[destAddr] = lzEndpointAddr;\n }\n\n function setRelayerPrice(\n uint128 _dstPriceRatio,\n uint128 _dstGasPriceInWei,\n uint128 _dstNativeAmtCap,\n uint64 _baseGas,\n uint64 _gasPerByte\n ) external {\n relayerFeeConfig.dstPriceRatio = _dstPriceRatio;\n relayerFeeConfig.dstGasPriceInWei = _dstGasPriceInWei;\n relayerFeeConfig.dstNativeAmtCap = _dstNativeAmtCap;\n relayerFeeConfig.baseGas = _baseGas;\n relayerFeeConfig.gasPerByte = _gasPerByte;\n }\n\n function setProtocolFee(uint _zroFee, uint _nativeBP) external {\n protocolFeeConfig.zroFee = _zroFee;\n protocolFeeConfig.nativeBP = _nativeBP;\n }\n\n function setOracleFee(uint _oracleFee) external {\n oracleFee = _oracleFee;\n }\n\n function setDefaultAdapterParams(bytes memory _adapterParams) external {\n defaultAdapterParams = _adapterParams;\n }\n\n // --------------------- Internal Functions ---------------------\n // simulates the relayer pushing through the rest of the msgs that got delayed due to the stored payload\n function _clearMsgQue(uint16 _srcChainId, bytes calldata _path) internal {\n QueuedPayload[] storage msgs = msgsToDeliver[_srcChainId][_path];\n\n // warning, might run into gas issues trying to forward through a bunch of queued msgs\n while (msgs.length > 0) {\n QueuedPayload memory payload = msgs[msgs.length - 1];\n ILayerZeroReceiver(payload.dstAddress).lzReceive(_srcChainId, _path, payload.nonce, payload.payload);\n msgs.pop();\n }\n }\n\n function _getProtocolFees(\n bool _payInZro,\n uint _relayerFee,\n uint _oracleFee\n ) internal view returns (uint) {\n if (_payInZro) {\n return protocolFeeConfig.zroFee;\n } else {\n return ((_relayerFee + _oracleFee) * protocolFeeConfig.nativeBP) / 10000;\n }\n }\n\n function _getRelayerFee(\n uint16, /* _dstChainId */\n uint16, /* _outboundProofType */\n address, /* _userApplication */\n uint _payloadSize,\n bytes memory _adapterParams\n ) internal view returns (uint) {\n (uint16 txType, uint extraGas, uint dstNativeAmt, ) = LzLib.decodeAdapterParams(_adapterParams);\n uint totalRemoteToken; // = baseGas + extraGas + requiredNativeAmount\n if (txType == 2) {\n require(relayerFeeConfig.dstNativeAmtCap >= dstNativeAmt, \"LayerZeroMock: dstNativeAmt too large \");\n totalRemoteToken += dstNativeAmt;\n }\n // remoteGasTotal = dstGasPriceInWei * (baseGas + extraGas)\n uint remoteGasTotal = relayerFeeConfig.dstGasPriceInWei * (relayerFeeConfig.baseGas + extraGas);\n totalRemoteToken += remoteGasTotal;\n\n // tokenConversionRate = dstPrice / localPrice\n // basePrice = totalRemoteToken * tokenConversionRate\n uint basePrice = (totalRemoteToken * relayerFeeConfig.dstPriceRatio) / 10**10;\n\n // pricePerByte = (dstGasPriceInWei * gasPerBytes) * tokenConversionRate\n uint pricePerByte = (relayerFeeConfig.dstGasPriceInWei * relayerFeeConfig.gasPerByte * relayerFeeConfig.dstPriceRatio) / 10**10;\n\n return basePrice + _payloadSize * pricePerByte;\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/NonblockingLzApp.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./LzApp.sol\";\nimport \"../libraries/ExcessivelySafeCall.sol\";\n\n/*\n * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel\n * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking\n * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)\n */\nabstract contract NonblockingLzApp is LzApp {\n using ExcessivelySafeCall for address;\n\n constructor(address _endpoint) LzApp(_endpoint) {}\n\n mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages;\n\n event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);\n event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);\n\n // overriding the virtual function in LzReceiver\n function _blockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual override {\n (bool success, bytes memory reason) = address(this).excessivelySafeCall(\n gasleft(),\n 150,\n abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload)\n );\n if (!success) {\n _storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason);\n }\n }\n\n function _storeFailedMessage(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload,\n bytes memory _reason\n ) internal virtual {\n failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);\n emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);\n }\n\n function nonblockingLzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public virtual {\n // only internal transaction\n require(_msgSender() == address(this), \"NonblockingLzApp: caller must be LzApp\");\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n //@notice override this function\n function _nonblockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual;\n\n function retryMessage(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public payable virtual {\n // assert there is message to retry\n bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];\n require(payloadHash != bytes32(0), \"NonblockingLzApp: no stored message\");\n require(keccak256(_payload) == payloadHash, \"NonblockingLzApp: invalid payload\");\n // clear the stored message\n failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0);\n // execute the message. revert if it fails again\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash);\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n function __Ownable2Step_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() external {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n _requireNotPaused();\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n _requirePaused();\n _;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Throws if the contract is paused.\n */\n function _requireNotPaused() internal view virtual {\n require(!paused(), \"Pausable: paused\");\n }\n\n /**\n * @dev Throws if the contract is not paused.\n */\n function _requirePaused() internal view virtual {\n require(paused(), \"Pausable: not paused\");\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" + }, + "@venusprotocol/solidity-utilities/contracts/validators.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Thrown if the supplied value is 0 where it is not allowed\nerror ZeroValueNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n}\n\n/// @notice Checks if the provided value is nonzero, reverts otherwise\n/// @param value_ Value to check\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\nfunction ensureNonzeroValue(uint256 value_) pure {\n if (value_ == 0) {\n revert ZeroValueNotAllowed();\n }\n}\n" + }, + "contracts/Cross-chain/BaseOmnichainControllerDest.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npragma solidity 0.8.25;\n\nimport { NonblockingLzApp } from \"@layerzerolabs/solidity-examples/contracts/lzApp/NonblockingLzApp.sol\";\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title BaseOmnichainControllerDest\n * @author Venus\n * @dev This contract is the base for the Omnichain controller destination contract\n * It provides functionality related to daily command limits and pausability\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\nabstract contract BaseOmnichainControllerDest is NonblockingLzApp, Pausable {\n /**\n * @notice Maximum daily limit for receiving commands from Binance chain\n */\n uint256 public maxDailyReceiveLimit;\n\n /**\n * @notice Total received commands within the last 24-hour window from Binance chain\n */\n uint256 public last24HourCommandsReceived;\n\n /**\n * @notice Timestamp when the last 24-hour window started from Binance chain\n */\n uint256 public last24HourReceiveWindowStart;\n\n /**\n * @notice Emitted when the maximum daily limit for receiving command from Binance chain is modified\n */\n event SetMaxDailyReceiveLimit(uint256 oldMaxLimit, uint256 newMaxLimit);\n\n constructor(address endpoint_) NonblockingLzApp(endpoint_) {\n ensureNonzeroAddress(endpoint_);\n }\n\n /**\n * @notice Sets the maximum daily limit for receiving commands\n * @param limit_ Number of commands\n * @custom:access Only Owner\n * @custom:event Emits SetMaxDailyReceiveLimit with old and new limit\n */\n function setMaxDailyReceiveLimit(uint256 limit_) external onlyOwner {\n emit SetMaxDailyReceiveLimit(maxDailyReceiveLimit, limit_);\n maxDailyReceiveLimit = limit_;\n }\n\n /**\n * @notice Triggers the paused state of the controller\n * @custom:access Only owner\n */\n function pause() external onlyOwner {\n _pause();\n }\n\n /**\n * @notice Triggers the resume state of the controller\n * @custom:access Only owner\n */\n function unpause() external onlyOwner {\n _unpause();\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishappening\n */\n function renounceOwnership() public override {}\n\n /**\n * @notice Check eligibility to receive commands\n * @param noOfCommands_ Number of commands to be received\n */\n function _isEligibleToReceive(uint256 noOfCommands_) internal {\n uint256 currentBlockTimestamp = block.timestamp;\n\n // Load values for the 24-hour window checks for receiving\n uint256 receivedInWindow = last24HourCommandsReceived;\n\n // Check if the time window has changed (more than 24 hours have passed)\n if (currentBlockTimestamp - last24HourReceiveWindowStart > 1 days) {\n receivedInWindow = noOfCommands_;\n last24HourReceiveWindowStart = currentBlockTimestamp;\n } else {\n receivedInWindow += noOfCommands_;\n }\n\n // Revert if the received amount exceeds the daily limit\n require(receivedInWindow <= maxDailyReceiveLimit, \"Daily Transaction Limit Exceeded\");\n\n // Update the received amount for the 24-hour window\n last24HourCommandsReceived = receivedInWindow;\n }\n}\n" + }, + "contracts/Cross-chain/BaseOmnichainControllerSrc.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npragma solidity 0.8.25;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { IAccessControlManagerV8 } from \"./../Governance/IAccessControlManagerV8.sol\";\n\n/**\n * @title BaseOmnichainControllerSrc\n * @dev This contract is the base for the Omnichain controller source contracts.\n * It provides functionality related to daily command limits and pausability.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract BaseOmnichainControllerSrc is Ownable, Pausable {\n /**\n * @notice ACM (Access Control Manager) contract address\n */\n address public accessControlManager;\n\n /**\n * @notice Maximum daily limit for commands from the local chain\n */\n mapping(uint16 => uint256) public chainIdToMaxDailyLimit;\n\n /**\n * @notice Total commands transferred within the last 24-hour window from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourCommandsSent;\n\n /**\n * @notice Timestamp when the last 24-hour window started from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourWindowStart;\n /**\n * @notice Timestamp when the last proposal sent from the local chain to dest chain\n */\n mapping(uint16 => uint256) public chainIdToLastProposalSentTimestamp;\n\n /**\n * @notice Emitted when the maximum daily limit of commands from the local chain is modified\n */\n event SetMaxDailyLimit(uint16 indexed chainId, uint256 oldMaxLimit, uint256 newMaxLimit);\n /*\n * @notice Emitted when the address of ACM is updated\n */\n event NewAccessControlManager(address indexed oldAccessControlManager, address indexed newAccessControlManager);\n\n constructor(address accessControlManager_) {\n ensureNonzeroAddress(accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Sets the limit of daily (24 Hour) command amount\n * @param chainId_ Destination chain id\n * @param limit_ Number of commands\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetMaxDailyLimit with old and new limit and its corresponding chain id\n */\n function setMaxDailyLimit(uint16 chainId_, uint256 limit_) external {\n _ensureAllowed(\"setMaxDailyLimit(uint16,uint256)\");\n emit SetMaxDailyLimit(chainId_, chainIdToMaxDailyLimit[chainId_], limit_);\n chainIdToMaxDailyLimit[chainId_] = limit_;\n }\n\n /**\n * @notice Triggers the paused state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function pause() external {\n _ensureAllowed(\"pause()\");\n _pause();\n }\n\n /**\n * @notice Triggers the resume state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function unpause() external {\n _ensureAllowed(\"unpause()\");\n _unpause();\n }\n\n /**\n * @notice Sets the address of Access Control Manager (ACM)\n * @param accessControlManager_ The new address of the Access Control Manager\n * @custom:access Only owner\n * @custom:event Emits NewAccessControlManager with old and new access control manager addresses\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n ensureNonzeroAddress(accessControlManager_);\n emit NewAccessControlManager(accessControlManager, accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishap\n */\n function renounceOwnership() public override {}\n\n /**\n * @notice Check eligibility to send commands\n * @param dstChainId_ Destination chain id\n * @param noOfCommands_ Number of commands to send\n */\n function _isEligibleToSend(uint16 dstChainId_, uint256 noOfCommands_) internal {\n // Load values for the 24-hour window checks\n uint256 currentBlockTimestamp = block.timestamp;\n uint256 lastDayWindowStart = chainIdToLast24HourWindowStart[dstChainId_];\n uint256 commandsSentInWindow = chainIdToLast24HourCommandsSent[dstChainId_];\n uint256 maxDailyLimit = chainIdToMaxDailyLimit[dstChainId_];\n uint256 lastProposalSentTimestamp = chainIdToLastProposalSentTimestamp[dstChainId_];\n\n // Check if the time window has changed (more than 24 hours have passed)\n if (currentBlockTimestamp - lastDayWindowStart > 1 days) {\n commandsSentInWindow = noOfCommands_;\n chainIdToLast24HourWindowStart[dstChainId_] = currentBlockTimestamp;\n } else {\n commandsSentInWindow += noOfCommands_;\n }\n\n // Revert if the amount exceeds the daily limit\n require(commandsSentInWindow <= maxDailyLimit, \"Daily Transaction Limit Exceeded\");\n // Revert if the last proposal is already sent in current block i.e multiple proposals cannot be sent within the same block.timestamp\n require(lastProposalSentTimestamp != currentBlockTimestamp, \"Multiple bridging in a proposal\");\n\n // Update the amount for the 24-hour window\n chainIdToLast24HourCommandsSent[dstChainId_] = commandsSentInWindow;\n // Update the last sent proposal timestamp\n chainIdToLastProposalSentTimestamp[dstChainId_] = currentBlockTimestamp;\n }\n\n /**\n * @notice Ensure that the caller has permission to execute a specific function\n * @param functionSig_ Function signature to be checked for permission\n */\n function _ensureAllowed(string memory functionSig_) internal view {\n require(\n IAccessControlManagerV8(accessControlManager).isAllowedToCall(msg.sender, functionSig_),\n \"access denied\"\n );\n }\n}\n" + }, + "contracts/Cross-chain/interfaces/IOmnichainGovernanceExecutor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\ninterface IOmnichainGovernanceExecutor {\n /**\n * @notice Transfers ownership of the contract to the specified address\n * @param addr The address to which ownership will be transferred\n */\n function transferOwnership(address addr) external;\n\n /**\n * @notice Sets the source message sender address\n * @param srcChainId_ The LayerZero id of a source chain\n * @param srcAddress_ The address of the contract on the source chain\n */\n function setTrustedRemoteAddress(uint16 srcChainId_, bytes calldata srcAddress_) external;\n}\n" + }, + "contracts/Cross-chain/interfaces/ITimelock.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/**\n * @title ITimelock\n * @author Venus\n * @dev Interface for Timelock contract\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\ninterface ITimelock {\n /**\n * @notice Delay period for the transaction queue\n */\n function delay() external view returns (uint256);\n\n /**\n * @notice Required period to execute a proposal transaction\n */\n function GRACE_PERIOD() external view returns (uint256);\n\n /**\n * @notice Method for accepting a proposed admin\n */\n function acceptAdmin() external;\n\n /**\n * @notice Method to propose a new admin authorized to call timelock functions. This should be the Governor Contract.\n */\n function setPendingAdmin(address pendingAdmin) external;\n\n /**\n * @notice Show mapping of queued transactions\n * @param hash Transaction hash\n */\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n /**\n * @notice Called for each action when queuing a proposal\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Hash of the queued transaction\n */\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n /**\n * @notice Called to cancel a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n */\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n /**\n * @notice Called to execute a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Result of function call\n */\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/Cross-chain/OmnichainExecutorOwner.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { AccessControlledV8 } from \"../Governance/AccessControlledV8.sol\";\nimport { IOmnichainGovernanceExecutor } from \"./interfaces/IOmnichainGovernanceExecutor.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title OmnichainExecutorOwner\n * @author Venus\n * @notice OmnichainProposalSender contract acts as a governance and access control mechanism,\n * allowing owner to upsert signature of OmnichainGovernanceExecutor contract,\n * also contains function to transfer the ownership of contract as well.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract OmnichainExecutorOwner is AccessControlledV8 {\n /**\n * @custom:oz-upgrades-unsafe-allow state-variable-immutable\n */\n IOmnichainGovernanceExecutor public immutable OMNICHAIN_GOVERNANCE_EXECUTOR;\n\n /**\n * @notice Stores function signature corresponding to their 4 bytes hash value\n */\n mapping(bytes4 => string) public functionRegistry;\n\n /**\n * @notice Event emitted when function registry updated\n */\n event FunctionRegistryChanged(string indexed signature, bool active);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address omnichainGovernanceExecutor_) {\n require(omnichainGovernanceExecutor_ != address(0), \"Address must not be zero\");\n OMNICHAIN_GOVERNANCE_EXECUTOR = IOmnichainGovernanceExecutor(omnichainGovernanceExecutor_);\n _disableInitializers();\n }\n\n /**\n * @notice Initialize the contract\n * @param accessControlManager_ Address of access control manager\n */\n function initialize(address accessControlManager_) external initializer {\n require(accessControlManager_ != address(0), \"Address must not be zero\");\n __AccessControlled_init(accessControlManager_);\n }\n\n /**\n * @notice Sets the source message sender address\n * @param srcChainId_ The LayerZero id of a source chain\n * @param srcAddress_ The address of the contract on the source chain\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetTrustedRemoteAddress with source chain Id and source address\n */\n function setTrustedRemoteAddress(uint16 srcChainId_, bytes calldata srcAddress_) external {\n _checkAccessAllowed(\"setTrustedRemoteAddress(uint16,bytes)\");\n require(srcChainId_ != 0, \"ChainId must not be zero\");\n ensureNonzeroAddress(address(uint160(bytes20(srcAddress_))));\n require(srcAddress_.length == 20, \"Source address must be 20 bytes long\");\n OMNICHAIN_GOVERNANCE_EXECUTOR.setTrustedRemoteAddress(srcChainId_, srcAddress_);\n }\n\n /**\n * @notice Invoked when called function does not exist in the contract\n * @param data_ Calldata containing the encoded function call\n * @return Result of function call\n * @custom:access Controlled by Access Control Manager\n */\n fallback(bytes calldata data_) external returns (bytes memory) {\n string memory fun = functionRegistry[msg.sig];\n require(bytes(fun).length != 0, \"Function not found\");\n _checkAccessAllowed(fun);\n (bool ok, bytes memory res) = address(OMNICHAIN_GOVERNANCE_EXECUTOR).call(data_);\n require(ok, \"call failed\");\n return res;\n }\n\n /**\n * @notice A registry of functions that are allowed to be executed from proposals\n * @param signatures_ Function signature to be added or removed\n * @param active_ bool value, should be true to add function\n * @custom:access Only owner\n */\n function upsertSignature(string[] calldata signatures_, bool[] calldata active_) external onlyOwner {\n uint256 signatureLength = signatures_.length;\n require(signatureLength == active_.length, \"Input arrays must have the same length\");\n for (uint256 i; i < signatureLength; ++i) {\n bytes4 sigHash = bytes4(keccak256(bytes(signatures_[i])));\n bytes memory signature = bytes(functionRegistry[sigHash]);\n if (active_[i] && signature.length == 0) {\n functionRegistry[sigHash] = signatures_[i];\n emit FunctionRegistryChanged(signatures_[i], true);\n } else if (!active_[i] && signature.length != 0) {\n delete functionRegistry[sigHash];\n emit FunctionRegistryChanged(signatures_[i], false);\n }\n }\n }\n\n /**\n * @notice This function transfer the ownership of the executor from this contract to new owner\n * @param newOwner_ New owner of the governanceExecutor\n * @custom:access Controlled by AccessControlManager\n */\n\n function transferBridgeOwnership(address newOwner_) external {\n _checkAccessAllowed(\"transferBridgeOwnership(address)\");\n require(newOwner_ != address(0), \"Address must not be zero\");\n OMNICHAIN_GOVERNANCE_EXECUTOR.transferOwnership(newOwner_);\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishappening\n */\n function renounceOwnership() public virtual override {}\n}\n" + }, + "contracts/Cross-chain/OmnichainGovernanceExecutor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.25;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { BytesLib } from \"@layerzerolabs/solidity-examples/contracts/libraries/BytesLib.sol\";\nimport { ExcessivelySafeCall } from \"@layerzerolabs/solidity-examples/contracts/libraries/ExcessivelySafeCall.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { BaseOmnichainControllerDest } from \"./BaseOmnichainControllerDest.sol\";\nimport { ITimelock } from \"./interfaces/ITimelock.sol\";\n\n/**\n * @title OmnichainGovernanceExecutor\n * @notice Executes the proposal transactions sent from the main chain\n * @dev The owner of this contract controls LayerZero configuration. When used in production the owner will be OmnichainExecutor\n * This implementation is non-blocking, meaning the failed messages will not block the future messages from the source.\n * For the blocking behavior, derive the contract from LzApp.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\ncontract OmnichainGovernanceExecutor is ReentrancyGuard, BaseOmnichainControllerDest {\n using BytesLib for bytes;\n using ExcessivelySafeCall for address;\n\n enum ProposalType {\n NORMAL,\n FASTTRACK,\n CRITICAL\n }\n\n struct Proposal {\n /** Unique id for looking up a proposal */\n uint256 id;\n /** The timestamp that the proposal will be available for execution, set once the vote succeeds */\n uint256 eta;\n /** The ordered list of target addresses for calls to be made */\n address[] targets;\n /** The ordered list of values (i.e. msg.value) to be passed to the calls to be made */\n uint256[] values;\n /** The ordered list of function signatures to be called */\n string[] signatures;\n /** The ordered list of calldata to be passed to each call */\n bytes[] calldatas;\n /** Flag marking whether the proposal has been canceled */\n bool canceled;\n /** Flag marking whether the proposal has been executed */\n bool executed;\n /** The type of the proposal */\n uint8 proposalType;\n }\n /*\n * @notice Possible states that a proposal may be in\n */\n enum ProposalState {\n Canceled,\n Queued,\n Executed\n }\n\n /**\n * @notice A privileged role that can cancel any proposal\n */\n address public guardian;\n\n /**\n * @notice Stores BNB chain layerzero endpoint id\n */\n uint16 public srcChainId;\n\n /**\n * @notice Last proposal count received\n */\n uint256 public lastProposalReceived;\n\n /**\n * @notice The official record of all proposals ever proposed\n */\n mapping(uint256 => Proposal) public proposals;\n\n /**\n * @notice Mapping containing Timelock addresses for each proposal type\n */\n mapping(uint256 => ITimelock) public proposalTimelocks;\n\n /**\n * @notice Represents queue state of proposal\n */\n mapping(uint256 => bool) public queued;\n\n /**\n * @notice Emitted when proposal is received\n */\n event ProposalReceived(\n uint256 indexed proposalId,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint8 proposalType\n );\n\n /**\n * @notice Emitted when proposal is queued\n */\n event ProposalQueued(uint256 indexed id, uint256 eta);\n\n /**\n * Emitted when proposal executed\n */\n event ProposalExecuted(uint256 indexed id);\n\n /**\n * @notice Emitted when proposal failed\n */\n event ReceivePayloadFailed(uint16 indexed srcChainId, bytes indexed srcAddress, uint64 nonce, bytes reason);\n\n /**\n * @notice Emitted when proposal is canceled\n */\n event ProposalCanceled(uint256 indexed id);\n\n /**\n * @notice Emitted when timelock added\n */\n event TimelockAdded(uint8 routeType, address indexed oldTimelock, address indexed newTimelock);\n\n /**\n * @notice Emitted when source layerzero endpoint id is updated\n */\n event SetSrcChainId(uint16 indexed oldSrcChainId, uint16 indexed newSrcChainId);\n\n /**\n * @notice Emitted when new guardian address is set\n */\n event NewGuardian(address indexed oldGuardian, address indexed newGuardian);\n\n /**\n * @notice Emitted when pending admin of Timelock is updated\n */\n event SetTimelockPendingAdmin(address, uint8);\n\n /**\n * @notice Thrown when proposal ID is invalid\n */\n error InvalidProposalId();\n\n constructor(address endpoint_, address guardian_, uint16 srcChainId_) BaseOmnichainControllerDest(endpoint_) {\n ensureNonzeroAddress(guardian_);\n guardian = guardian_;\n srcChainId = srcChainId_;\n }\n\n /**\n * @notice Update source layerzero endpoint id\n * @param srcChainId_ The new source chain id to be set\n * @custom:event Emit SetSrcChainId with old and new source id\n * @custom:access Only owner\n */\n function setSrcChainId(uint16 srcChainId_) external onlyOwner {\n emit SetSrcChainId(srcChainId, srcChainId_);\n srcChainId = srcChainId_;\n }\n\n /**\n * @notice Sets the new executor guardian\n * @param newGuardian The address of the new guardian\n * @custom:access Must be call by guardian or owner\n * @custom:event Emit NewGuardian with old and new guardian address\n */\n function setGuardian(address newGuardian) external {\n require(\n msg.sender == guardian || msg.sender == owner(),\n \"OmnichainGovernanceExecutor::setGuardian: owner or guardian only\"\n );\n ensureNonzeroAddress(newGuardian);\n emit NewGuardian(guardian, newGuardian);\n guardian = newGuardian;\n }\n\n /**\n * @notice Add timelocks to the ProposalTimelocks mapping\n * @param timelocks_ Array of addresses of all 3 timelocks\n * @custom:access Only owner\n * @custom:event Emits TimelockAdded with old and new timelock and route type\n */\n function addTimelocks(ITimelock[] memory timelocks_) external onlyOwner {\n uint8 length = uint8(type(ProposalType).max) + 1;\n require(\n timelocks_.length == length,\n \"OmnichainGovernanceExecutor::addTimelocks:number of timelocks should match the number of governance routes\"\n );\n for (uint8 i; i < length; ++i) {\n ensureNonzeroAddress(address(timelocks_[i]));\n emit TimelockAdded(i, address(proposalTimelocks[i]), address(timelocks_[i]));\n proposalTimelocks[i] = timelocks_[i];\n }\n }\n\n /**\n * @notice Executes a queued proposal if eta has passed\n * @param proposalId_ Id of proposal that is to be executed\n * @custom:event Emits ProposalExecuted with proposal id of executed proposal\n */\n function execute(uint256 proposalId_) external nonReentrant {\n require(\n state(proposalId_) == ProposalState.Queued,\n \"OmnichainGovernanceExecutor::execute: proposal can only be executed if it is queued\"\n );\n\n Proposal storage proposal = proposals[proposalId_];\n proposal.executed = true;\n ITimelock timelock = proposalTimelocks[proposal.proposalType];\n uint256 eta = proposal.eta;\n uint256 length = proposal.targets.length;\n\n emit ProposalExecuted(proposalId_);\n\n for (uint256 i; i < length; ++i) {\n timelock.executeTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n delete queued[proposalId_];\n }\n\n /**\n * @notice Cancels a proposal only if sender is the guardian and proposal is not executed\n * @param proposalId_ Id of proposal that is to be canceled\n * @custom:access Sender must be the guardian\n * @custom:event Emits ProposalCanceled with proposal id of the canceled proposal\n */\n function cancel(uint256 proposalId_) external {\n require(\n state(proposalId_) == ProposalState.Queued,\n \"OmnichainGovernanceExecutor::cancel: proposal should be queued and not executed\"\n );\n Proposal storage proposal = proposals[proposalId_];\n require(msg.sender == guardian, \"OmnichainGovernanceExecutor::cancel: sender must be guardian\");\n\n proposal.canceled = true;\n ITimelock timelock = proposalTimelocks[proposal.proposalType];\n uint256 eta = proposal.eta;\n uint256 length = proposal.targets.length;\n\n emit ProposalCanceled(proposalId_);\n\n for (uint256 i; i < length; ++i) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n delete queued[proposalId_];\n }\n\n /**\n * @notice Sets the new pending admin of the Timelock\n * @param pendingAdmin_ Address of new pending admin\n * @param proposalType_ Type of proposal\n * @custom:access Only owner\n * @custom:event Emits SetTimelockPendingAdmin with new pending admin and proposal type\n */\n function setTimelockPendingAdmin(address pendingAdmin_, uint8 proposalType_) external onlyOwner {\n uint8 proposalTypeLength = uint8(type(ProposalType).max) + 1;\n require(\n proposalType_ < proposalTypeLength,\n \"OmnichainGovernanceExecutor::setTimelockPendingAdmin: invalid proposal type\"\n );\n\n proposalTimelocks[proposalType_].setPendingAdmin(pendingAdmin_);\n emit SetTimelockPendingAdmin(pendingAdmin_, proposalType_);\n }\n\n /**\n * @notice Resends a previously failed message\n * @param srcChainId_ Source chain Id\n * @param srcAddress_ Source address => local app address + remote app address\n * @param nonce_ Nonce to identify failed message\n * @param payload_ The payload of the message to be retried\n * @custom:access Only owner\n */\n function retryMessage(\n uint16 srcChainId_,\n bytes calldata srcAddress_,\n uint64 nonce_,\n bytes calldata payload_\n ) public payable override onlyOwner nonReentrant {\n require(\n keccak256(trustedRemoteLookup[srcChainId_]) == keccak256(srcAddress_),\n \"OmnichainGovernanceExecutor::retryMessage: not a trusted remote\"\n );\n super.retryMessage(srcChainId_, srcAddress_, nonce_, payload_);\n }\n\n /**\n * @notice Gets the state of a proposal\n * @param proposalId_ The id of the proposal\n * @return Proposal state\n */\n function state(uint256 proposalId_) public view returns (ProposalState) {\n Proposal storage proposal = proposals[proposalId_];\n if (proposal.canceled) {\n return ProposalState.Canceled;\n } else if (proposal.executed) {\n return ProposalState.Executed;\n } else if (queued[proposalId_]) {\n // queued only when proposal is received\n return ProposalState.Queued;\n } else {\n revert InvalidProposalId();\n }\n }\n\n /**\n * @notice Process blocking LayerZero receive request\n * @param srcChainId_ Source chain Id\n * @param srcAddress_ Source address from which payload is received\n * @param nonce_ Nonce associated with the payload to prevent replay attacks\n * @param payload_ Encoded payload containing proposal information\n * @custom:event Emit ReceivePayloadFailed if call fails\n */\n function _blockingLzReceive(\n uint16 srcChainId_,\n bytes memory srcAddress_,\n uint64 nonce_,\n bytes memory payload_\n ) internal virtual override {\n require(srcChainId_ == srcChainId, \"OmnichainGovernanceExecutor::_blockingLzReceive: invalid source chain id\");\n bytes32 hashedPayload = keccak256(payload_);\n bytes memory callData = abi.encodeCall(this.nonblockingLzReceive, (srcChainId_, srcAddress_, nonce_, payload_));\n\n (bool success, bytes memory reason) = address(this).excessivelySafeCall(gasleft() - 30000, 150, callData);\n // try-catch all errors/exceptions\n if (!success) {\n failedMessages[srcChainId_][srcAddress_][nonce_] = hashedPayload;\n emit ReceivePayloadFailed(srcChainId_, srcAddress_, nonce_, reason); // Retrieve payload from the src side tx if needed to clear\n }\n }\n\n /**\n * @notice Process non blocking LayerZero receive request\n * @param payload_ Encoded payload containing proposal information\n * @custom:event Emit ProposalReceived\n */\n function _nonblockingLzReceive(\n uint16,\n bytes memory,\n uint64,\n bytes memory payload_\n ) internal virtual override whenNotPaused {\n (bytes memory payload, uint256 pId) = abi.decode(payload_, (bytes, uint256));\n (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n uint8 pType\n ) = abi.decode(payload, (address[], uint256[], string[], bytes[], uint8));\n require(proposals[pId].id == 0, \"OmnichainGovernanceExecutor::_nonblockingLzReceive: duplicate proposal\");\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"OmnichainGovernanceExecutor::_nonblockingLzReceive: proposal function information arity mismatch\"\n );\n require(\n pType < uint8(type(ProposalType).max) + 1,\n \"OmnichainGovernanceExecutor::_nonblockingLzReceive: invalid proposal type\"\n );\n _isEligibleToReceive(targets.length);\n\n Proposal memory newProposal = Proposal({\n id: pId,\n eta: 0,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas,\n canceled: false,\n executed: false,\n proposalType: pType\n });\n\n proposals[pId] = newProposal;\n lastProposalReceived = pId;\n\n emit ProposalReceived(newProposal.id, targets, values, signatures, calldatas, pType);\n _queue(pId);\n }\n\n /**\n * @notice Queue proposal for execution\n * @param proposalId_ Proposal to be queued\n * @custom:event Emit ProposalQueued with proposal id and eta\n */\n function _queue(uint256 proposalId_) internal {\n Proposal storage proposal = proposals[proposalId_];\n uint256 eta = block.timestamp + proposalTimelocks[proposal.proposalType].delay();\n\n proposal.eta = eta;\n queued[proposalId_] = true;\n uint8 proposalType = proposal.proposalType;\n uint256 length = proposal.targets.length;\n emit ProposalQueued(proposalId_, eta);\n\n for (uint256 i; i < length; ++i) {\n _queueOrRevertInternal(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta,\n proposalType\n );\n }\n }\n\n /**\n * @notice Check for unique proposal\n * @param target_ Address of the contract with the method to be called\n * @param value_ Native token amount sent with the transaction\n * @param signature_ Signature of the function to be called\n * @param data_ Arguments to be passed to the function when called\n * @param eta_ Timestamp after which the transaction can be executed\n * @param proposalType_ Type of proposal\n */\n function _queueOrRevertInternal(\n address target_,\n uint256 value_,\n string memory signature_,\n bytes memory data_,\n uint256 eta_,\n uint8 proposalType_\n ) internal {\n require(\n !proposalTimelocks[proposalType_].queuedTransactions(\n keccak256(abi.encode(target_, value_, signature_, data_, eta_))\n ),\n \"OmnichainGovernanceExecutor::queueOrRevertInternal: identical proposal action already queued at eta\"\n );\n\n proposalTimelocks[proposalType_].queueTransaction(target_, value_, signature_, data_, eta_);\n }\n}\n" + }, + "contracts/Cross-chain/OmnichainProposalSender.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.25;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { ILayerZeroEndpoint } from \"@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { BaseOmnichainControllerSrc } from \"./BaseOmnichainControllerSrc.sol\";\n\n/**\n * @title OmnichainProposalSender\n * @author Venus\n * @notice OmnichainProposalSender contract builds upon the functionality of its parent contract , BaseOmnichainControllerSrc\n * It sends a proposal's data to remote chains for execution after the proposal passes on the main chain\n * when used with GovernorBravo, the owner of this contract must be set to the Timelock contract\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract OmnichainProposalSender is ReentrancyGuard, BaseOmnichainControllerSrc {\n /**\n * @notice Stores the total number of remote proposals\n */\n uint256 public proposalCount;\n\n /**\n * @notice Execution hashes of failed messages\n * @dev [proposalId] -> [executionHash]\n */\n mapping(uint256 => bytes32) public storedExecutionHashes;\n\n /**\n * @notice LayerZero endpoint for sending messages to remote chains\n */\n ILayerZeroEndpoint public immutable LZ_ENDPOINT;\n\n /**\n * @notice Specifies the allowed path for sending messages (remote chainId => remote app address + local app address)\n */\n mapping(uint16 => bytes) public trustedRemoteLookup;\n\n /**\n * @notice Emitted when a remote message receiver is set for the remote chain\n */\n event SetTrustedRemoteAddress(uint16 indexed remoteChainId, bytes oldRemoteAddress, bytes newRemoteAddress);\n\n /**\n * @notice Event emitted when trusted remote sets to empty\n */\n event TrustedRemoteRemoved(uint16 indexed chainId);\n\n /**\n * @notice Emitted when a proposal execution request is sent to the remote chain\n */\n event ExecuteRemoteProposal(uint16 indexed remoteChainId, uint256 proposalId, bytes payload);\n\n /**\n * @notice Emitted when a previously failed message is successfully sent to the remote chain\n */\n event ClearPayload(uint256 indexed proposalId, bytes32 executionHash);\n\n /**\n * @notice Emitted when an execution hash of a failed message is saved\n */\n event StorePayload(\n uint256 indexed proposalId,\n uint16 indexed remoteChainId,\n bytes payload,\n bytes adapterParams,\n uint256 value,\n bytes reason\n );\n /**\n * @notice Emitted while fallback withdraw\n */\n event FallbackWithdraw(address indexed receiver, uint256 value);\n\n constructor(\n ILayerZeroEndpoint lzEndpoint_,\n address accessControlManager_\n ) BaseOmnichainControllerSrc(accessControlManager_) {\n ensureNonzeroAddress(address(lzEndpoint_));\n LZ_ENDPOINT = lzEndpoint_;\n }\n\n /**\n * @notice Estimates LayerZero fees for cross-chain message delivery to the remote chain\n * @dev The estimated fees are the minimum required; it's recommended to increase the fees amount when sending a message. The unused amount will be refunded\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param payload_ The payload to be sent to the remote chain. It's computed as follows:\n * payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param useZro_ Bool that indicates whether to pay in ZRO tokens or not\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @return nativeFee The amount of fee in the native gas token (e.g. ETH)\n * @return zroFee The amount of fee in ZRO token\n */\n function estimateFees(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bool useZro_,\n bytes calldata adapterParams_\n ) external view returns (uint256, uint256) {\n return LZ_ENDPOINT.estimateFees(remoteChainId_, address(this), payload_, useZro_, adapterParams_);\n }\n\n /**\n * @notice Remove trusted remote from storage\n * @param remoteChainId_ The chain's id corresponds to setting the trusted remote to empty\n * @custom:access Controlled by Access Control Manager\n * @custom:event Emit TrustedRemoteRemoved with remote chain id\n */\n function removeTrustedRemote(uint16 remoteChainId_) external {\n _ensureAllowed(\"removeTrustedRemote(uint16)\");\n require(trustedRemoteLookup[remoteChainId_].length != 0, \"OmnichainProposalSender: trusted remote not found\");\n delete trustedRemoteLookup[remoteChainId_];\n emit TrustedRemoteRemoved(remoteChainId_);\n }\n\n /**\n * @notice Sends a message to execute a remote proposal\n * @dev Stores the hash of the execution parameters if sending fails (e.g., due to insufficient fees)\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(targets, values, signatures, calldatas, proposalType)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction. This must be either address(this) or tx.origin\n * @custom:event Emits ExecuteRemoteProposal with remote chain id, proposal ID and payload on success\n * @custom:event Emits StorePayload with last stored payload proposal ID ,remote chain id , payload, adapter params , values and reason for failure\n * @custom:access Controlled by Access Control Manager\n */\n function execute(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_\n ) external payable whenNotPaused {\n _ensureAllowed(\"execute(uint16,bytes,bytes,address)\");\n\n // A zero value will result in a failed message; therefore, a positive value is required to send a message across the chain.\n require(msg.value > 0, \"OmnichainProposalSender: value cannot be zero\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n _validateProposal(remoteChainId_, payload_);\n uint256 _pId = ++proposalCount;\n bytes memory payload = abi.encode(payload_, _pId);\n\n try\n LZ_ENDPOINT.send{ value: msg.value }(\n remoteChainId_,\n trustedRemote,\n payload,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n )\n {\n emit ExecuteRemoteProposal(remoteChainId_, _pId, payload);\n } catch (bytes memory reason) {\n storedExecutionHashes[_pId] = keccak256(abi.encode(remoteChainId_, payload, adapterParams_, msg.value));\n emit StorePayload(_pId, remoteChainId_, payload, adapterParams_, msg.value, reason);\n }\n }\n\n /**\n * @notice Resends a previously failed message\n * @dev Allows providing more fees if needed. The extra fees will be refunded to the caller\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction.\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:access Controlled by Access Control Manager\n */\n function retryExecute(\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_,\n uint256 originalValue_\n ) external payable whenNotPaused nonReentrant {\n _ensureAllowed(\"retryExecute(uint256,uint16,bytes,bytes,address,uint256)\");\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n (bytes memory payload, ) = abi.decode(payload_, (bytes, uint256));\n _validateProposal(remoteChainId_, payload);\n\n require(\n keccak256(abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_)) == hash,\n \"OmnichainProposalSender: invalid execution params\"\n );\n\n delete storedExecutionHashes[pId_];\n\n emit ClearPayload(pId_, hash);\n\n LZ_ENDPOINT.send{ value: originalValue_ + msg.value }(\n remoteChainId_,\n trustedRemote,\n payload_,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n );\n }\n\n /**\n * @notice Clear previously failed message\n * @param to_ Address of the receiver\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:access Only owner\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:event Emits FallbackWithdraw with receiver and amount\n */\n function fallbackWithdraw(\n address to_,\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n uint256 originalValue_\n ) external onlyOwner nonReentrant {\n ensureNonzeroAddress(to_);\n require(originalValue_ > 0, \"OmnichainProposalSender: invalid native amount\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n\n bytes memory execution = abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_);\n require(keccak256(execution) == hash, \"OmnichainProposalSender: invalid execution params\");\n\n delete storedExecutionHashes[pId_];\n\n emit FallbackWithdraw(to_, originalValue_);\n emit ClearPayload(pId_, hash);\n\n // Transfer the native to the `to_` address\n (bool sent, ) = to_.call{ value: originalValue_ }(\"\");\n require(sent, \"Call failed\");\n }\n\n /**\n * @notice Sets the remote message receiver address\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param newRemoteAddress_ The address of the contract on the remote chain to receive messages sent by this contract\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetTrustedRemoteAddress with remote chain Id and remote address\n */\n function setTrustedRemoteAddress(uint16 remoteChainId_, bytes calldata newRemoteAddress_) external {\n _ensureAllowed(\"setTrustedRemoteAddress(uint16,bytes)\");\n require(remoteChainId_ != 0, \"OmnichainProposalSender: chainId must not be zero\");\n ensureNonzeroAddress(address(uint160(bytes20(newRemoteAddress_))));\n require(newRemoteAddress_.length == 20, \"OmnichainProposalSender: remote address must be 20 bytes long\");\n bytes memory oldRemoteAddress = trustedRemoteLookup[remoteChainId_];\n trustedRemoteLookup[remoteChainId_] = abi.encodePacked(newRemoteAddress_, address(this));\n emit SetTrustedRemoteAddress(remoteChainId_, oldRemoteAddress, trustedRemoteLookup[remoteChainId_]);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId for the pending config change\n * @param configType_ The type of configuration. Every messaging library has its own convention\n * @param config_ The configuration in bytes. It can encode arbitrary content\n * @custom:access Controlled by AccessControlManager\n */\n function setConfig(uint16 version_, uint16 chainId_, uint256 configType_, bytes calldata config_) external {\n _ensureAllowed(\"setConfig(uint16,uint16,uint256,bytes)\");\n LZ_ENDPOINT.setConfig(version_, chainId_, configType_, config_);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ New messaging library version\n * @custom:access Controlled by AccessControlManager\n */\n function setSendVersion(uint16 version_) external {\n _ensureAllowed(\"setSendVersion(uint16)\");\n LZ_ENDPOINT.setSendVersion(version_);\n }\n\n /**\n * @notice Gets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId\n * @param configType_ Type of configuration. Every messaging library has its own convention\n */\n function getConfig(uint16 version_, uint16 chainId_, uint256 configType_) external view returns (bytes memory) {\n return LZ_ENDPOINT.getConfig(version_, chainId_, address(this), configType_);\n }\n\n function _validateProposal(uint16 remoteChainId_, bytes memory payload_) internal {\n (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n\n ) = abi.decode(payload_, (address[], uint[], string[], bytes[], uint8));\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"OmnichainProposalSender: proposal function information arity mismatch\"\n );\n _isEligibleToSend(remoteChainId_, targets.length);\n }\n}\n" + }, + "contracts/Governance/AccessControlledV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlledV8\n * @author Venus\n * @notice This contract is helper between access control manager and actual contract. This contract further inherited by other contract (using solidity 0.8.13)\n * to integrate access controlled mechanism. It provides initialise methods and verifying access methods.\n */\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n /// @notice Access control manager contract\n IAccessControlManagerV8 private _accessControlManager;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when access control manager contract address is changed\n event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n /// @notice Thrown when the action is prohibited by AccessControlManager\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Sets the address of AccessControlManager\n * @dev Admin function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n * @custom:event Emits NewAccessControlManager event\n * @custom:access Only Governance\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Returns the address of the access control manager contract\n */\n function accessControlManager() external view returns (IAccessControlManagerV8) {\n return _accessControlManager;\n }\n\n /**\n * @dev Internal function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n */\n function _setAccessControlManager(address accessControlManager_) internal {\n require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n address oldAccessControlManager = address(_accessControlManager);\n _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n }\n\n /**\n * @notice Reverts if the call is not allowed by AccessControlManager\n * @param signature Method signature\n */\n function _checkAccessAllowed(string memory signature) internal view {\n bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n }\n}\n" + }, + "contracts/Governance/AccessControlManager.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlManager\n * @author Venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl extending it in a way to standartize access control within Venus Smart Contract Ecosystem.\n * @notice Access control plays a crucial role in the Venus governance model. It is used to restrict functions so that they can only be called from one\n * account or list of accounts (EOA or Contract Accounts).\n *\n * The implementation of `AccessControlManager`(https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/AccessControlManager.sol)\n * inherits the [Open Zeppelin AccessControl](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol)\n * contract as a base for role management logic. There are two role types: admin and granular permissions.\n * \n * ## Granular Roles\n * \n * Granular roles are built by hashing the contract address and its function signature. For example, given contract `Foo` with function `Foo.bar()` which\n * is guarded by ACM, calling `giveRolePermission` for account B do the following:\n * \n * 1. Compute `keccak256(contractFooAddress,functionSignatureBar)`\n * 1. Add the computed role to the roles of account B\n * 1. Account B now can call `ContractFoo.bar()`\n * \n * ## Admin Roles\n * \n * Admin roles allow for an address to call a function signature on any contract guarded by the `AccessControlManager`. This is particularly useful for\n * contracts created by factories.\n * \n * For Admin roles a null address is hashed in place of the contract address (`keccak256(0x0000000000000000000000000000000000000000,functionSignatureBar)`.\n * \n * In the previous example, giving account B the admin role, account B will have permissions to call the `bar()` function on any contract that is guarded by\n * ACM, not only contract A.\n * \n * ## Protocol Integration\n * \n * All restricted functions in Venus Protocol use a hook to ACM in order to check if the caller has the right permission to call the guarded function.\n * `AccessControlledV5` and `AccessControlledV8` abstract contract makes this integration easier. They call ACM's external method\n * `isAllowedToCall(address caller, string functionSig)`. Here is an example of how `setCollateralFactor` function in `Comptroller` is integrated with ACM:\n\n```\n contract Comptroller is [...] AccessControlledV8 {\n [...]\n function setCollateralFactor(VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external {\n _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n [...]\n }\n }\n```\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n /// @notice Emitted when an account is given a permission to a certain contract function\n /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n /// can call any contract function with this signature\n event PermissionGranted(address account, address contractAddress, string functionSig);\n\n /// @notice Emitted when an account is revoked a permission to a certain contract function\n event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n constructor() {\n // Grant the contract deployer the default admin role: it will be able\n // to grant and revoke any roles\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n /**\n * @notice Gives a function call permission to one single account\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * @param contractAddress address of contract for which call permissions will be granted\n * @dev if contractAddress is zero address, the account can access the specified function\n * on **any** contract managed by this ACL\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @param accountToPermit account that will be given access to the contract function\n * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n */\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n grantRole(role, accountToPermit);\n emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n }\n\n /**\n * @notice Revokes an account's permission to a particular function call\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * \t\tMay emit a {RoleRevoked} event.\n * @param contractAddress address of contract for which call permissions will be revoked\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n */\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n revokeRole(role, accountToRevoke);\n emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n * @param account for which call permissions will be checked\n * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n *\n */\n function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n if (hasRole(role, account)) {\n return true;\n } else {\n role = keccak256(abi.encodePacked(address(0), functionSig));\n return hasRole(role, account);\n }\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n * @param account for which call permissions will be checked against\n * @param contractAddress address of the restricted contract\n * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n */\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n return hasRole(role, account);\n }\n}\n" + }, + "contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + }, + "contracts/Governance/TimelockV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title TimelockV8\n * @author Venus\n * @notice The Timelock contract using solidity V8.\n * This contract also differs from the original timelock because it has a virtual function to get minimum delays\n * and allow test deployments to override the value.\n */\ncontract TimelockV8 {\n /// @notice Required period to execute a proposal transaction\n uint256 private constant DEFAULT_GRACE_PERIOD = 14 days;\n\n /// @notice Minimum amount of time a proposal transaction must be queued\n uint256 private constant DEFAULT_MINIMUM_DELAY = 1 hours;\n\n /// @notice Maximum amount of time a proposal transaction must be queued\n uint256 private constant DEFAULT_MAXIMUM_DELAY = 30 days;\n\n /// @notice Timelock admin authorized to queue and execute transactions\n address public admin;\n\n /// @notice Account proposed as the next admin\n address public pendingAdmin;\n\n /// @notice Period for a proposal transaction to be queued\n uint256 public delay;\n\n /// @notice Mapping of queued transactions\n mapping(bytes32 => bool) public queuedTransactions;\n\n /// @notice Event emitted when a new admin is accepted\n event NewAdmin(address indexed oldAdmin, address indexed newAdmin);\n\n /// @notice Event emitted when a new admin is proposed\n event NewPendingAdmin(address indexed newPendingAdmin);\n\n /// @notice Event emitted when a new delay is proposed\n event NewDelay(uint256 indexed oldDelay, uint256 indexed newDelay);\n\n /// @notice Event emitted when a proposal transaction has been cancelled\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /// @notice Event emitted when a proposal transaction has been executed\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /// @notice Event emitted when a proposal transaction has been queued\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n constructor(address admin_, uint256 delay_) {\n require(delay_ >= MINIMUM_DELAY(), \"Timelock::constructor: Delay must exceed minimum delay.\");\n require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n ensureNonzeroAddress(admin_);\n\n admin = admin_;\n delay = delay_;\n }\n\n fallback() external payable {}\n\n /**\n * @notice Setter for the transaction queue delay\n * @param delay_ The new delay period for the transaction queue\n * @custom:access Sender must be Timelock itself\n * @custom:event Emit NewDelay with old and new delay\n */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY(), \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n emit NewDelay(delay, delay_);\n delay = delay_;\n }\n\n /**\n * @notice Return grace period\n * @return The duration of the grace period, specified as a uint256 value.\n */\n function GRACE_PERIOD() public view virtual returns (uint256) {\n return DEFAULT_GRACE_PERIOD;\n }\n\n /**\n * @notice Return required minimum delay\n * @return Minimum delay\n */\n function MINIMUM_DELAY() public view virtual returns (uint256) {\n return DEFAULT_MINIMUM_DELAY;\n }\n\n /**\n * @notice Return required maximum delay\n * @return Maximum delay\n */\n function MAXIMUM_DELAY() public view virtual returns (uint256) {\n return DEFAULT_MAXIMUM_DELAY;\n }\n\n /**\n * @notice Method for accepting a proposed admin\n * @custom:access Sender must be pending admin\n * @custom:event Emit NewAdmin with old and new admin\n */\n function acceptAdmin() public {\n require(msg.sender == pendingAdmin, \"Timelock::acceptAdmin: Call must come from pendingAdmin.\");\n emit NewAdmin(admin, msg.sender);\n admin = msg.sender;\n pendingAdmin = address(0);\n }\n\n /**\n * @notice Method to propose a new admin authorized to call timelock functions. This should be the Governor Contract\n * @param pendingAdmin_ Address of the proposed admin\n * @custom:access Sender must be Timelock contract itself or admin\n * @custom:event Emit NewPendingAdmin with new pending admin\n */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this) || msg.sender == admin,\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n ensureNonzeroAddress(pendingAdmin_);\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Called for each action when queuing a proposal\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Hash of the queued transaction\n * @custom:access Sender must be admin\n * @custom:event Emit QueueTransaction\n */\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp() + delay,\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(!queuedTransactions[txHash], \"Timelock::queueTransaction: transaction already queued.\");\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Called to cancel a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @custom:access Sender must be admin\n * @custom:event Emit CancelTransaction\n */\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(queuedTransactions[txHash], \"Timelock::cancelTransaction: transaction is not queued yet.\");\n delete (queuedTransactions[txHash]);\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Called to execute a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Result of function call\n * @custom:access Sender must be admin\n * @custom:event Emit ExecuteTransaction\n */\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(queuedTransactions[txHash], \"Timelock::executeTransaction: Transaction hasn't been queued.\");\n require(getBlockTimestamp() >= eta, \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\");\n require(getBlockTimestamp() <= eta + GRACE_PERIOD(), \"Timelock::executeTransaction: Transaction is stale.\");\n\n delete (queuedTransactions[txHash]);\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call{ value: value }(callData);\n require(success, \"Timelock::executeTransaction: Transaction execution reverted.\");\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice Returns the current block timestamp\n * @return The current block timestamp\n */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/test/MockAccessTest.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"../Governance/AccessControlledV8.sol\";\nimport \"@layerzerolabs/solidity-examples/contracts/lzApp/mocks/LZEndpointMock.sol\";\n\ncontract MockAccessTest is AccessControlledV8 {\n /**\n * @param accessControlManager Access control manager contract address\n */\n function initialize(address accessControlManager) external initializer {\n __AccessControlled_init_unchained(accessControlManager);\n }\n}\n" + }, + "contracts/test/MockXVSVault.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\ncontract MockXVSVault {\n /* solhint-disable no-unused-vars */\n function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96) {\n /* solhint-enable no-unused-vars */\n return 0;\n }\n}\n" + }, + "contracts/test/TestTimelockV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { TimelockV8 } from \"../Governance/TimelockV8.sol\";\n\ncontract TestTimelockV8 is TimelockV8 {\n constructor(address admin_, uint256 delay_) public TimelockV8(admin_, delay_) {}\n\n function GRACE_PERIOD() public view override returns (uint256) {\n return 1 hours;\n }\n\n function MINIMUM_DELAY() public view override returns (uint256) {\n return 1;\n }\n\n function MAXIMUM_DELAY() public view override returns (uint256) {\n return 1 hours;\n }\n}\n" + }, + "contracts/Utils/ACMCommandsAggregator.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IAccessControlManagerV8 } from \"../Governance/IAccessControlManagerV8.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title ACMCommandsAggregator\n * @author Venus\n * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\n */\ncontract ACMCommandsAggregator {\n /*\n * @notice Struct to store permission details\n */\n struct Permission {\n /*\n * @notice Address of the contract\n */\n address contractAddress;\n /*\n * @notice Function signature\n */\n string functionSig;\n /*\n * @notice Address of the account\n */\n address account;\n }\n\n /**\n * @notice Access control manager contract\n */\n IAccessControlManagerV8 public immutable ACM;\n\n /*\n * @notice 2D array to store grant permissions in batches\n */\n Permission[][] public grantPermissions;\n\n /*\n * @notice 2D array to store revoke permissions in batches\n */\n Permission[][] public revokePermissions;\n\n /*\n * @notice Event emitted when grant permissions are added\n */\n event GrantPermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when revoke permissions are added\n */\n event RevokePermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when grant permissions are executed\n */\n event GrantPermissionsExecuted(uint256 index);\n\n /*\n * @notice Event emitted when revoke permissions are executed\n */\n event RevokePermissionsExecuted(uint256 index);\n\n /*\n * @notice Error to be thrown when permissions are empty\n */\n error EmptyPermissions();\n\n /*\n * @notice Constructor to set the access control manager\n * @param _acm Address of the access control manager\n */\n constructor(IAccessControlManagerV8 _acm) {\n ensureNonzeroAddress(address(_acm));\n ACM = _acm;\n }\n\n /*\n * @notice Function to add grant permissions\n * @param _permissions Array of permissions\n * @custom:event Emits GrantPermissionsAdded event\n */\n function addGrantPermissions(Permission[] memory _permissions) external {\n if (_permissions.length == 0) {\n revert EmptyPermissions();\n }\n\n uint256 index = grantPermissions.length;\n grantPermissions.push();\n\n for (uint256 i; i < _permissions.length; ++i) {\n grantPermissions[index].push(\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n );\n }\n\n emit GrantPermissionsAdded(index);\n }\n\n /*\n * @notice Function to add revoke permissions\n * @param _permissions Array of permissions\n * @custom:event Emits RevokePermissionsAdded event\n */\n function addRevokePermissions(Permission[] memory _permissions) external {\n if (_permissions.length == 0) {\n revert EmptyPermissions();\n }\n\n uint256 index = revokePermissions.length;\n revokePermissions.push();\n\n for (uint256 i; i < _permissions.length; ++i) {\n revokePermissions[index].push(\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n );\n }\n\n emit RevokePermissionsAdded(index);\n }\n\n /*\n * @notice Function to execute grant permissions\n * @param index Index of the permissions array\n * @custom:event Emits GrantPermissionsExecuted event\n */\n function executeGrantPermissions(uint256 index) external {\n uint256 length = grantPermissions[index].length;\n for (uint256 i; i < length; ++i) {\n Permission memory permission = grantPermissions[index][i];\n ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n }\n\n emit GrantPermissionsExecuted(index);\n }\n\n /*\n * @notice Function to execute revoke permissions\n * @param index Index of the permissions array\n * @custom:event Emits RevokePermissionsExecuted event\n */\n function executeRevokePermissions(uint256 index) external {\n uint256 length = revokePermissions[index].length;\n for (uint256 i; i < length; ++i) {\n Permission memory permission = revokePermissions[index][i];\n ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n }\n\n emit RevokePermissionsExecuted(index);\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 10000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/arbitrumsepolia_addresses.json b/deployments/arbitrumsepolia_addresses.json index 08754853..afd88ec0 100644 --- a/deployments/arbitrumsepolia_addresses.json +++ b/deployments/arbitrumsepolia_addresses.json @@ -2,6 +2,7 @@ "name": "arbitrumsepolia", "chainId": "421614", "addresses": { + "ACMCommandsAggregator": "0x4fCbfE445396f31005b3Fd2F6DE2A986d6E2dCB5", "AccessControlManager": "0xa36AD96441cB931D8dFEAAaC97D3FaB4B39E590F", "CriticalTimelock": "0x0b32Be083f7041608E023007e7802430396a2123", "DefaultProxyAdmin": "0xA78A1Df376c3CEeBC5Fab574fe6EdDbbF76fd03e", diff --git a/deployments/opbnbtestnet.json b/deployments/opbnbtestnet.json index 3628f1ce..87f38791 100644 --- a/deployments/opbnbtestnet.json +++ b/deployments/opbnbtestnet.json @@ -2,6 +2,251 @@ "name": "opbnbtestnet", "chainId": "5611", "contracts": { + "ACMCommandsAggregator": { + "address": "0xbDd501dB1B0D6aab299CE69ef5B86C8578947AD0", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "_acm", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantPermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "revokePermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + }, "AccessControlManager": { "address": "0x049f77F7046266d27C3bC96376f53C17Ef09c986", "abi": [ diff --git a/deployments/opbnbtestnet/ACMCommandsAggregator.json b/deployments/opbnbtestnet/ACMCommandsAggregator.json new file mode 100644 index 00000000..78cc4ed9 --- /dev/null +++ b/deployments/opbnbtestnet/ACMCommandsAggregator.json @@ -0,0 +1,366 @@ +{ + "address": "0xbDd501dB1B0D6aab299CE69ef5B86C8578947AD0", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "_acm", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantPermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "revokePermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x38e04d82106d913b8e47c39f0565068f4dd9e6a220075cf79430cad40c1a7458", + "receipt": { + "to": null, + "from": "0x464779C41C5f1Be598853C1F87bCC7087Ea75f28", + "contractAddress": "0xbDd501dB1B0D6aab299CE69ef5B86C8578947AD0", + "transactionIndex": 1, + "gasUsed": "937641", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x0b65ee81e78e484e6f28bae81ac923eefc868cf5b769a6450478a6416740c499", + "transactionHash": "0x38e04d82106d913b8e47c39f0565068f4dd9e6a220075cf79430cad40c1a7458", + "logs": [], + "blockNumber": 41162016, + "cumulativeGasUsed": "981504", + "status": 1, + "byzantium": true + }, + "args": ["0x049f77F7046266d27C3bC96376f53C17Ef09c986"], + "numDeployments": 1, + "solcInputHash": "8462bae4a0ff7e7203ecab090cdf091c", + "metadata": "{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IAccessControlManagerV8\",\"name\":\"_acm\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPermissions\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"GrantPermissionsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"GrantPermissionsExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"RevokePermissionsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"RevokePermissionsExecuted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ACM\",\"outputs\":[{\"internalType\":\"contract IAccessControlManagerV8\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"internalType\":\"struct ACMCommandsAggregator.Permission[]\",\"name\":\"_permissions\",\"type\":\"tuple[]\"}],\"name\":\"addGrantPermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"internalType\":\"struct ACMCommandsAggregator.Permission[]\",\"name\":\"_permissions\",\"type\":\"tuple[]\"}],\"name\":\"addRevokePermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"executeGrantPermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"executeRevokePermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"grantPermissions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"revokePermissions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Venus\",\"kind\":\"dev\",\"methods\":{},\"title\":\"ACMCommandsAggregator\",\"version\":1},\"userdoc\":{\"errors\":{\"ZeroAddressNotAllowed()\":[{\"notice\":\"Thrown if the supplied address is a zero address where it is not allowed\"}]},\"kind\":\"user\",\"methods\":{\"ACM()\":{\"notice\":\"Access control manager contract\"}},\"notice\":\"This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Utils/ACMCommandsAggregator.sol\":\"ACMCommandsAggregator\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n *\\n * _Available since v3.1._\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@venusprotocol/solidity-utilities/contracts/validators.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\\nerror ZeroAddressNotAllowed();\\n\\n/// @notice Thrown if the supplied value is 0 where it is not allowed\\nerror ZeroValueNotAllowed();\\n\\n/// @notice Checks if the provided address is nonzero, reverts otherwise\\n/// @param address_ Address to check\\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\\nfunction ensureNonzeroAddress(address address_) pure {\\n if (address_ == address(0)) {\\n revert ZeroAddressNotAllowed();\\n }\\n}\\n\\n/// @notice Checks if the provided value is nonzero, reverts otherwise\\n/// @param value_ Value to check\\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\\nfunction ensureNonzeroValue(uint256 value_) pure {\\n if (value_ == 0) {\\n revert ZeroValueNotAllowed();\\n }\\n}\\n\",\"keccak256\":\"0xdb88e14d50dd21889ca3329d755673d022c47e8da005b6a545c7f69c2c4b7b86\",\"license\":\"BSD-3-Clause\"},\"contracts/Governance/IAccessControlManagerV8.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\nimport \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\n\\n/**\\n * @title IAccessControlManagerV8\\n * @author Venus\\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\\n */\\ninterface IAccessControlManagerV8 is IAccessControl {\\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\\n\\n function revokeCallPermission(\\n address contractAddress,\\n string calldata functionSig,\\n address accountToRevoke\\n ) external;\\n\\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\\n\\n function hasPermission(\\n address account,\\n address contractAddress,\\n string calldata functionSig\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xaa29b098440d0b3a131c5ecdf25ce548790c1b5ac7bf9b5c0264b6af6f7a1e0b\",\"license\":\"BSD-3-Clause\"},\"contracts/Utils/ACMCommandsAggregator.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\nimport { IAccessControlManagerV8 } from \\\"../Governance/IAccessControlManagerV8.sol\\\";\\nimport { ensureNonzeroAddress } from \\\"@venusprotocol/solidity-utilities/contracts/validators.sol\\\";\\n\\n/**\\n * @title ACMCommandsAggregator\\n * @author Venus\\n * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\\n */\\ncontract ACMCommandsAggregator {\\n /*\\n * @notice Struct to store permission details\\n */\\n struct Permission {\\n /*\\n * @notice Address of the contract\\n */\\n address contractAddress;\\n /*\\n * @notice Function signature\\n */\\n string functionSig;\\n /*\\n * @notice Address of the account\\n */\\n address account;\\n }\\n\\n /**\\n * @notice Access control manager contract\\n */\\n IAccessControlManagerV8 public immutable ACM;\\n\\n /*\\n * @notice 2D array to store grant permissions in batches\\n */\\n Permission[][] public grantPermissions;\\n\\n /*\\n * @notice 2D array to store revoke permissions in batches\\n */\\n Permission[][] public revokePermissions;\\n\\n /*\\n * @notice Event emitted when grant permissions are added\\n */\\n event GrantPermissionsAdded(uint256 index);\\n\\n /*\\n * @notice Event emitted when revoke permissions are added\\n */\\n event RevokePermissionsAdded(uint256 index);\\n\\n /*\\n * @notice Event emitted when grant permissions are executed\\n */\\n event GrantPermissionsExecuted(uint256 index);\\n\\n /*\\n * @notice Event emitted when revoke permissions are executed\\n */\\n event RevokePermissionsExecuted(uint256 index);\\n\\n /*\\n * @notice Error to be thrown when permissions are empty\\n */\\n error EmptyPermissions();\\n\\n /*\\n * @notice Constructor to set the access control manager\\n * @param _acm Address of the access control manager\\n */\\n constructor(IAccessControlManagerV8 _acm) {\\n ensureNonzeroAddress(address(_acm));\\n ACM = _acm;\\n }\\n\\n /*\\n * @notice Function to add grant permissions\\n * @param _permissions Array of permissions\\n * @custom:event Emits GrantPermissionsAdded event\\n */\\n function addGrantPermissions(Permission[] memory _permissions) external {\\n if (_permissions.length == 0) {\\n revert EmptyPermissions();\\n }\\n\\n uint256 index = grantPermissions.length;\\n grantPermissions.push();\\n\\n for (uint256 i; i < _permissions.length; ++i) {\\n grantPermissions[index].push(\\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\\n );\\n }\\n\\n emit GrantPermissionsAdded(index);\\n }\\n\\n /*\\n * @notice Function to add revoke permissions\\n * @param _permissions Array of permissions\\n * @custom:event Emits RevokePermissionsAdded event\\n */\\n function addRevokePermissions(Permission[] memory _permissions) external {\\n if (_permissions.length == 0) {\\n revert EmptyPermissions();\\n }\\n\\n uint256 index = revokePermissions.length;\\n revokePermissions.push();\\n\\n for (uint256 i; i < _permissions.length; ++i) {\\n revokePermissions[index].push(\\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\\n );\\n }\\n\\n emit RevokePermissionsAdded(index);\\n }\\n\\n /*\\n * @notice Function to execute grant permissions\\n * @param index Index of the permissions array\\n * @custom:event Emits GrantPermissionsExecuted event\\n */\\n function executeGrantPermissions(uint256 index) external {\\n uint256 length = grantPermissions[index].length;\\n for (uint256 i; i < length; ++i) {\\n Permission memory permission = grantPermissions[index][i];\\n ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account);\\n }\\n\\n emit GrantPermissionsExecuted(index);\\n }\\n\\n /*\\n * @notice Function to execute revoke permissions\\n * @param index Index of the permissions array\\n * @custom:event Emits RevokePermissionsExecuted event\\n */\\n function executeRevokePermissions(uint256 index) external {\\n uint256 length = revokePermissions[index].length;\\n for (uint256 i; i < length; ++i) {\\n Permission memory permission = revokePermissions[index][i];\\n ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account);\\n }\\n\\n emit RevokePermissionsExecuted(index);\\n }\\n}\\n\",\"keccak256\":\"0xe642b8f0e0fedc74d31196197bc7d78b43b44eab556c07ec74d6b75ccf8d0f8c\",\"license\":\"BSD-3-Clause\"}},\"version\":1}", + "bytecode": "0x60a0604052348015600f57600080fd5b506040516110c73803806110c7833981016040819052602c91606c565b6033816043565b6001600160a01b0316608052609a565b6001600160a01b0381166069576040516342bcdf7f60e11b815260040160405180910390fd5b50565b600060208284031215607d57600080fd5b81516001600160a01b0381168114609357600080fd5b9392505050565b6080516110046100c360003960008181610100015281816102de0152610a0101526110046000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80639d6c76b81161005b5780639d6c76b8146100d5578063de46a235146100e8578063f9b80da1146100fb578063ff1575e11461014757600080fd5b806322473d8c14610082578063514aab87146100975780635666a5ea146100c2575b600080fd5b610095610090366004610ab8565b61015a565b005b6100aa6100a5366004610ad1565b61038d565b6040516100b993929190610af3565b60405180910390f35b6100956100d0366004610c59565b610492565b6100956100e3366004610c59565b610689565b6100956100f6366004610ab8565b61087f565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b9565b6100aa610155366004610ad1565b610aa8565b60006001828154811061016f5761016f610de1565b600091825260208220015491505b818110156103545760006001848154811061019a5761019a610de1565b9060005260206000200182815481106101b5576101b5610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161020290610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461022e90610e10565b801561027b5780601f106102505761010080835404028352916020019161027b565b820191906000526020600020905b81548152906001019060200180831161025e57829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f545f7a320000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363545f7a329361031693909291600401610af3565b600060405180830381600087803b15801561033057600080fd5b505af1158015610344573d6000803e3d6000fd5b505050505080600101905061017d565b506040518281527f1382323d6618527d8b03daa05db815f0490966e8b80679fe5ad3d868f84e1a71906020015b60405180910390a15050565b6000828154811061039d57600080fd5b9060005260206000200181815481106103b557600080fd5b60009182526020909120600390910201805460018201805473ffffffffffffffffffffffffffffffffffffffff90921694509192506103f390610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461041f90610e10565b801561046c5780601f106104415761010080835404028352916020019161046c565b820191906000526020600020905b81548152906001019060200180831161044f57829003601f168201915b5050506002909301549192505073ffffffffffffffffffffffffffffffffffffffff1683565b80516000036104cd576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805480820182556000918252905b825181101561065857600182815481106104f9576104f9610de1565b90600052602060002001604051806060016040528085848151811061052057610520610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061055957610559610de1565b602002602001015160200151815260200185848151811061057c5761057c610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906106019082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016104dd565b506040518181527f75922591bf2cec980645dc4a32bb7d5e8da9a15fda86dacf06f8402cecd1478f90602001610381565b80516000036106c4576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054600181018255818052905b825181101561084e57600082815481106106ef576106ef610de1565b90600052602060002001604051806060016040528085848151811061071657610716610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061074f5761074f610de1565b602002602001015160200151815260200185848151811061077257610772610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906107f79082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016106d3565b506040518181527ff8ca6ea7cc31be8572501c37ef5e9e8298be717fb881e0b1ca785aecc4d25e9f90602001610381565b600080828154811061089357610893610de1565b600091825260208220015491505b81811015610a775760008084815481106108bd576108bd610de1565b9060005260206000200182815481106108d8576108d8610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161092590610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461095190610e10565b801561099e5780601f106109735761010080835404028352916020019161099e565b820191906000526020600020905b81548152906001019060200180831161098157829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f584f6b600000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363584f6b6093610a3993909291600401610af3565b600060405180830381600087803b158015610a5357600080fd5b505af1158015610a67573d6000803e3d6000fd5b50505050508060010190506108a1565b506040518281527f01a805f459381af632ecab72ec192c3f9a4c72d26be089026ffd6636d82de98890602001610381565b6001828154811061039d57600080fd5b600060208284031215610aca57600080fd5b5035919050565b60008060408385031215610ae457600080fd5b50508035926020909101359150565b600073ffffffffffffffffffffffffffffffffffffffff8086168352602060606020850152855180606086015260005b81811015610b3f57878101830151868201608001528201610b23565b5060006080828701015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010193505050808416604084015250949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610bdb57610bdb610b89565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c2857610c28610b89565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c5457600080fd5b919050565b60006020808385031215610c6c57600080fd5b823567ffffffffffffffff80821115610c8457600080fd5b818501915085601f830112610c9857600080fd5b813581811115610caa57610caa610b89565b8060051b610cb9858201610be1565b9182528381018501918581019089841115610cd357600080fd5b86860192505b83831015610dd457823585811115610cf057600080fd5b86017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06060828d0382011215610d265760008081fd5b610d2e610bb8565b610d398a8401610c30565b815260408084013589811115610d4f5760008081fd5b8401603f81018f13610d615760008081fd5b8b8101358a811115610d7557610d75610b89565b610d858d86601f84011601610be1565b94508085528f83828401011115610d9c5760008081fd5b808383018e87013760008d82870101525050828b830152610dbf60608501610c30565b90820152845250509186019190860190610cd9565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c90821680610e2457607f821691505b602082108103610e5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610eaf576000816000526020600020601f850160051c81016020861015610e8c5750805b601f850160051c820191505b81811015610eab57828155600101610e98565b5050505b505050565b815167ffffffffffffffff811115610ece57610ece610b89565b610ee281610edc8454610e10565b84610e63565b602080601f831160018114610f355760008415610eff5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610eab565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610f8257888601518255948401946001909101908401610f63565b5085821015610fbe57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122090d4936e163063dfe747da5bf04cc06002b17436a13e78a30b2797e6219ebb2264736f6c63430008190033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80639d6c76b81161005b5780639d6c76b8146100d5578063de46a235146100e8578063f9b80da1146100fb578063ff1575e11461014757600080fd5b806322473d8c14610082578063514aab87146100975780635666a5ea146100c2575b600080fd5b610095610090366004610ab8565b61015a565b005b6100aa6100a5366004610ad1565b61038d565b6040516100b993929190610af3565b60405180910390f35b6100956100d0366004610c59565b610492565b6100956100e3366004610c59565b610689565b6100956100f6366004610ab8565b61087f565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b9565b6100aa610155366004610ad1565b610aa8565b60006001828154811061016f5761016f610de1565b600091825260208220015491505b818110156103545760006001848154811061019a5761019a610de1565b9060005260206000200182815481106101b5576101b5610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161020290610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461022e90610e10565b801561027b5780601f106102505761010080835404028352916020019161027b565b820191906000526020600020905b81548152906001019060200180831161025e57829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f545f7a320000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363545f7a329361031693909291600401610af3565b600060405180830381600087803b15801561033057600080fd5b505af1158015610344573d6000803e3d6000fd5b505050505080600101905061017d565b506040518281527f1382323d6618527d8b03daa05db815f0490966e8b80679fe5ad3d868f84e1a71906020015b60405180910390a15050565b6000828154811061039d57600080fd5b9060005260206000200181815481106103b557600080fd5b60009182526020909120600390910201805460018201805473ffffffffffffffffffffffffffffffffffffffff90921694509192506103f390610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461041f90610e10565b801561046c5780601f106104415761010080835404028352916020019161046c565b820191906000526020600020905b81548152906001019060200180831161044f57829003601f168201915b5050506002909301549192505073ffffffffffffffffffffffffffffffffffffffff1683565b80516000036104cd576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805480820182556000918252905b825181101561065857600182815481106104f9576104f9610de1565b90600052602060002001604051806060016040528085848151811061052057610520610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061055957610559610de1565b602002602001015160200151815260200185848151811061057c5761057c610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906106019082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016104dd565b506040518181527f75922591bf2cec980645dc4a32bb7d5e8da9a15fda86dacf06f8402cecd1478f90602001610381565b80516000036106c4576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054600181018255818052905b825181101561084e57600082815481106106ef576106ef610de1565b90600052602060002001604051806060016040528085848151811061071657610716610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061074f5761074f610de1565b602002602001015160200151815260200185848151811061077257610772610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906107f79082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016106d3565b506040518181527ff8ca6ea7cc31be8572501c37ef5e9e8298be717fb881e0b1ca785aecc4d25e9f90602001610381565b600080828154811061089357610893610de1565b600091825260208220015491505b81811015610a775760008084815481106108bd576108bd610de1565b9060005260206000200182815481106108d8576108d8610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161092590610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461095190610e10565b801561099e5780601f106109735761010080835404028352916020019161099e565b820191906000526020600020905b81548152906001019060200180831161098157829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f584f6b600000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363584f6b6093610a3993909291600401610af3565b600060405180830381600087803b158015610a5357600080fd5b505af1158015610a67573d6000803e3d6000fd5b50505050508060010190506108a1565b506040518281527f01a805f459381af632ecab72ec192c3f9a4c72d26be089026ffd6636d82de98890602001610381565b6001828154811061039d57600080fd5b600060208284031215610aca57600080fd5b5035919050565b60008060408385031215610ae457600080fd5b50508035926020909101359150565b600073ffffffffffffffffffffffffffffffffffffffff8086168352602060606020850152855180606086015260005b81811015610b3f57878101830151868201608001528201610b23565b5060006080828701015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010193505050808416604084015250949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610bdb57610bdb610b89565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c2857610c28610b89565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c5457600080fd5b919050565b60006020808385031215610c6c57600080fd5b823567ffffffffffffffff80821115610c8457600080fd5b818501915085601f830112610c9857600080fd5b813581811115610caa57610caa610b89565b8060051b610cb9858201610be1565b9182528381018501918581019089841115610cd357600080fd5b86860192505b83831015610dd457823585811115610cf057600080fd5b86017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06060828d0382011215610d265760008081fd5b610d2e610bb8565b610d398a8401610c30565b815260408084013589811115610d4f5760008081fd5b8401603f81018f13610d615760008081fd5b8b8101358a811115610d7557610d75610b89565b610d858d86601f84011601610be1565b94508085528f83828401011115610d9c5760008081fd5b808383018e87013760008d82870101525050828b830152610dbf60608501610c30565b90820152845250509186019190860190610cd9565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c90821680610e2457607f821691505b602082108103610e5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610eaf576000816000526020600020601f850160051c81016020861015610e8c5750805b601f850160051c820191505b81811015610eab57828155600101610e98565b5050505b505050565b815167ffffffffffffffff811115610ece57610ece610b89565b610ee281610edc8454610e10565b84610e63565b602080601f831160018114610f355760008415610eff5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610eab565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610f8257888601518255948401946001909101908401610f63565b5085821015610fbe57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122090d4936e163063dfe747da5bf04cc06002b17436a13e78a30b2797e6219ebb2264736f6c63430008190033", + "devdoc": { + "author": "Venus", + "kind": "dev", + "methods": {}, + "title": "ACMCommandsAggregator", + "version": 1 + }, + "userdoc": { + "errors": { + "ZeroAddressNotAllowed()": [ + { + "notice": "Thrown if the supplied address is a zero address where it is not allowed" + } + ] + }, + "kind": "user", + "methods": { + "ACM()": { + "notice": "Access control manager contract" + } + }, + "notice": "This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 8955, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "grantPermissions", + "offset": 0, + "slot": "0", + "type": "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage" + }, + { + "astId": 8960, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "revokePermissions", + "offset": 0, + "slot": "1", + "type": "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage": { + "base": "t_array(t_struct(Permission)8946_storage)dyn_storage", + "encoding": "dynamic_array", + "label": "struct ACMCommandsAggregator.Permission[][]", + "numberOfBytes": "32" + }, + "t_array(t_struct(Permission)8946_storage)dyn_storage": { + "base": "t_struct(Permission)8946_storage", + "encoding": "dynamic_array", + "label": "struct ACMCommandsAggregator.Permission[]", + "numberOfBytes": "32" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Permission)8946_storage": { + "encoding": "inplace", + "label": "struct ACMCommandsAggregator.Permission", + "members": [ + { + "astId": 8941, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "contractAddress", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 8943, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "functionSig", + "offset": 0, + "slot": "1", + "type": "t_string_storage" + }, + { + "astId": 8945, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "account", + "offset": 0, + "slot": "2", + "type": "t_address" + } + ], + "numberOfBytes": "96" + } + } + } +} diff --git a/deployments/opbnbtestnet/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json b/deployments/opbnbtestnet/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json new file mode 100644 index 00000000..12855c7e --- /dev/null +++ b/deployments/opbnbtestnet/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json @@ -0,0 +1,151 @@ +{ + "language": "Solidity", + "sources": { + "@layerzerolabs/solidity-examples/contracts/libraries/BytesLib.sol": { + "content": "// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\nlibrary BytesLib {\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(\n 0x40,\n and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n )\n )\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask)))\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(\n bytes memory _bytes,\n uint _start,\n uint _length\n ) internal pure returns (bytes memory) {\n require(_length + 31 >= _length, \"slice_overflow\");\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint _start) internal pure returns (uint) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n } eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for {\n\n } eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/libraries/ExcessivelySafeCall.sol": { + "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.7.6;\n\nlibrary ExcessivelySafeCall {\n uint constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(\n address _target,\n uint _gas,\n uint16 _maxCopy,\n bytes memory _calldata\n ) internal returns (bool, bytes memory) {\n // set up for assembly call\n uint _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly {\n _success := call(\n _gas, // gas\n _target, // recipient\n 0, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) {\n _toCopy := _maxCopy\n }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(\n address _target,\n uint _gas,\n uint16 _maxCopy,\n bytes memory _calldata\n ) internal view returns (bool, bytes memory) {\n // set up for assembly call\n uint _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly {\n _success := staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) {\n _toCopy := _maxCopy\n }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /**\n * @notice Swaps function selectors in encoded contract calls\n * @dev Allows reuse of encoded calldata for functions with identical\n * argument types but different names. It simply swaps out the first 4 bytes\n * for the new selector. This function modifies memory in place, and should\n * only be used with caution.\n * @param _newSelector The new 4-byte selector\n * @param _buf The encoded contract args\n */\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint _mask = LOW_28_MASK;\n assembly {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\n\ninterface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {\n // @notice send a LayerZero message to the specified address at a LayerZero endpoint.\n // @param _dstChainId - the destination chain identifier\n // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains\n // @param _payload - a custom bytes payload to send to the destination contract\n // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address\n // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction\n // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination\n function send(\n uint16 _dstChainId,\n bytes calldata _destination,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes calldata _adapterParams\n ) external payable;\n\n // @notice used by the messaging library to publish verified payload\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source contract (as bytes) at the source chain\n // @param _dstAddress - the address on destination chain\n // @param _nonce - the unbound message ordering nonce\n // @param _gasLimit - the gas limit for external contract execution\n // @param _payload - verified payload to send to the destination contract\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n address _dstAddress,\n uint64 _nonce,\n uint _gasLimit,\n bytes calldata _payload\n ) external;\n\n // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);\n\n // @notice get the outboundNonce from this source chain which, consequently, is always an EVM\n // @param _srcAddress - the source chain contract address\n function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);\n\n // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery\n // @param _dstChainId - the destination chain identifier\n // @param _userApplication - the user app address on this EVM chain\n // @param _payload - the custom message to send over LayerZero\n // @param _payInZRO - if false, user app pays the protocol fee in native token\n // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes calldata _payload,\n bool _payInZRO,\n bytes calldata _adapterParam\n ) external view returns (uint nativeFee, uint zroFee);\n\n // @notice get this Endpoint's immutable source identifier\n function getChainId() external view returns (uint16);\n\n // @notice the interface to retry failed message on this Endpoint destination\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n // @param _payload - the payload to be retried\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n bytes calldata _payload\n ) external;\n\n // @notice query if any STORED payload (message blocking) at the endpoint.\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);\n\n // @notice query if the _libraryAddress is valid for sending msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getSendLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the _libraryAddress is valid for receiving msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getReceiveLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the non-reentrancy guard for send() is on\n // @return true if the guard is on. false otherwise\n function isSendingPayload() external view returns (bool);\n\n // @notice query if the non-reentrancy guard for receive() is on\n // @return true if the guard is on. false otherwise\n function isReceivingPayload() external view returns (bool);\n\n // @notice get the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _userApplication - the contract address of the user application\n // @param _configType - type of configuration. every messaging library has its own convention.\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address _userApplication,\n uint _configType\n ) external view returns (bytes memory);\n\n // @notice get the send() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getSendVersion(address _userApplication) external view returns (uint16);\n\n // @notice get the lzReceive() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getReceiveVersion(address _userApplication) external view returns (uint16);\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroReceiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroReceiver {\n // @notice LayerZero endpoint will invoke this function to deliver the message on the destination\n // @param _srcChainId - the source endpoint identifier\n // @param _srcAddress - the source sending contract address from the source chain\n // @param _nonce - the ordered message nonce\n // @param _payload - the signed payload is the UA bytes has encoded to be sent\n function lzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) external;\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroUserApplicationConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroUserApplicationConfig {\n // @notice set the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _configType - type of configuration. every messaging library has its own convention.\n // @param _config - configuration in the bytes. can encode arbitrary content.\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint _configType,\n bytes calldata _config\n ) external;\n\n // @notice set the send() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setSendVersion(uint16 _version) external;\n\n // @notice set the lzReceive() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setReceiveVersion(uint16 _version) external;\n\n // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload\n // @param _srcChainId - the chainId of the source chain\n // @param _srcAddress - the contract address of the source contract at the source chain\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/libs/LzLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.6.0;\npragma experimental ABIEncoderV2;\n\nlibrary LzLib {\n // LayerZero communication\n struct CallParams {\n address payable refundAddress;\n address zroPaymentAddress;\n }\n\n //---------------------------------------------------------------------------\n // Address type handling\n\n struct AirdropParams {\n uint airdropAmount;\n bytes32 airdropAddress;\n }\n\n function buildAdapterParams(LzLib.AirdropParams memory _airdropParams, uint _uaGasLimit) internal pure returns (bytes memory adapterParams) {\n if (_airdropParams.airdropAmount == 0 && _airdropParams.airdropAddress == bytes32(0x0)) {\n adapterParams = buildDefaultAdapterParams(_uaGasLimit);\n } else {\n adapterParams = buildAirdropAdapterParams(_uaGasLimit, _airdropParams);\n }\n }\n\n // Build Adapter Params\n function buildDefaultAdapterParams(uint _uaGas) internal pure returns (bytes memory) {\n // txType 1\n // bytes [2 32 ]\n // fields [txType extraGas]\n return abi.encodePacked(uint16(1), _uaGas);\n }\n\n function buildAirdropAdapterParams(uint _uaGas, AirdropParams memory _params) internal pure returns (bytes memory) {\n require(_params.airdropAmount > 0, \"Airdrop amount must be greater than 0\");\n require(_params.airdropAddress != bytes32(0x0), \"Airdrop address must be set\");\n\n // txType 2\n // bytes [2 32 32 bytes[] ]\n // fields [txType extraGas dstNativeAmt dstNativeAddress]\n return abi.encodePacked(uint16(2), _uaGas, _params.airdropAmount, _params.airdropAddress);\n }\n\n function getGasLimit(bytes memory _adapterParams) internal pure returns (uint gasLimit) {\n require(_adapterParams.length == 34 || _adapterParams.length > 66, \"Invalid adapterParams\");\n assembly {\n gasLimit := mload(add(_adapterParams, 34))\n }\n }\n\n // Decode Adapter Params\n function decodeAdapterParams(bytes memory _adapterParams)\n internal\n pure\n returns (\n uint16 txType,\n uint uaGas,\n uint airdropAmount,\n address payable airdropAddress\n )\n {\n require(_adapterParams.length == 34 || _adapterParams.length > 66, \"Invalid adapterParams\");\n assembly {\n txType := mload(add(_adapterParams, 2))\n uaGas := mload(add(_adapterParams, 34))\n }\n require(txType == 1 || txType == 2, \"Unsupported txType\");\n require(uaGas > 0, \"Gas too low\");\n\n if (txType == 2) {\n assembly {\n airdropAmount := mload(add(_adapterParams, 66))\n airdropAddress := mload(add(_adapterParams, 86))\n }\n }\n }\n\n //---------------------------------------------------------------------------\n // Address type handling\n function bytes32ToAddress(bytes32 _bytes32Address) internal pure returns (address _address) {\n return address(uint160(uint(_bytes32Address)));\n }\n\n function addressToBytes32(address _address) internal pure returns (bytes32 _bytes32Address) {\n return bytes32(uint(uint160(_address)));\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/LzApp.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./interfaces/ILayerZeroReceiver.sol\";\nimport \"./interfaces/ILayerZeroUserApplicationConfig.sol\";\nimport \"./interfaces/ILayerZeroEndpoint.sol\";\nimport \"../libraries/BytesLib.sol\";\n\n/*\n * a generic LzReceiver implementation\n */\nabstract contract LzApp is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {\n using BytesLib for bytes;\n\n // ua can not send payload larger than this by default, but it can be changed by the ua owner\n uint public constant DEFAULT_PAYLOAD_SIZE_LIMIT = 10000;\n\n ILayerZeroEndpoint public immutable lzEndpoint;\n mapping(uint16 => bytes) public trustedRemoteLookup;\n mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;\n mapping(uint16 => uint) public payloadSizeLimitLookup;\n address public precrime;\n\n event SetPrecrime(address precrime);\n event SetTrustedRemote(uint16 _remoteChainId, bytes _path);\n event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);\n event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);\n\n constructor(address _endpoint) {\n lzEndpoint = ILayerZeroEndpoint(_endpoint);\n }\n\n function lzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public virtual override {\n // lzReceive must be called by the endpoint for security\n require(_msgSender() == address(lzEndpoint), \"LzApp: invalid endpoint caller\");\n\n bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];\n // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.\n require(\n _srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote),\n \"LzApp: invalid source sending contract\"\n );\n\n _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging\n function _blockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual;\n\n function _lzSend(\n uint16 _dstChainId,\n bytes memory _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams,\n uint _nativeFee\n ) internal virtual {\n bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];\n require(trustedRemote.length != 0, \"LzApp: destination chain is not a trusted source\");\n _checkPayloadSize(_dstChainId, _payload.length);\n lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);\n }\n\n function _checkGasLimit(\n uint16 _dstChainId,\n uint16 _type,\n bytes memory _adapterParams,\n uint _extraGas\n ) internal view virtual {\n uint providedGasLimit = _getGasLimit(_adapterParams);\n uint minGasLimit = minDstGasLookup[_dstChainId][_type];\n require(minGasLimit > 0, \"LzApp: minGasLimit not set\");\n require(providedGasLimit >= minGasLimit + _extraGas, \"LzApp: gas limit is too low\");\n }\n\n function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {\n require(_adapterParams.length >= 34, \"LzApp: invalid adapterParams\");\n assembly {\n gasLimit := mload(add(_adapterParams, 34))\n }\n }\n\n function _checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internal view virtual {\n uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId];\n if (payloadSizeLimit == 0) {\n // use default if not set\n payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;\n }\n require(_payloadSize <= payloadSizeLimit, \"LzApp: payload size is too large\");\n }\n\n //---------------------------UserApplication config----------------------------------------\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address,\n uint _configType\n ) external view returns (bytes memory) {\n return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);\n }\n\n // generic config for LayerZero user Application\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint _configType,\n bytes calldata _config\n ) external override onlyOwner {\n lzEndpoint.setConfig(_version, _chainId, _configType, _config);\n }\n\n function setSendVersion(uint16 _version) external override onlyOwner {\n lzEndpoint.setSendVersion(_version);\n }\n\n function setReceiveVersion(uint16 _version) external override onlyOwner {\n lzEndpoint.setReceiveVersion(_version);\n }\n\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {\n lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);\n }\n\n // _path = abi.encodePacked(remoteAddress, localAddress)\n // this function set the trusted path for the cross-chain communication\n function setTrustedRemote(uint16 _remoteChainId, bytes calldata _path) external onlyOwner {\n trustedRemoteLookup[_remoteChainId] = _path;\n emit SetTrustedRemote(_remoteChainId, _path);\n }\n\n function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external onlyOwner {\n trustedRemoteLookup[_remoteChainId] = abi.encodePacked(_remoteAddress, address(this));\n emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);\n }\n\n function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) {\n bytes memory path = trustedRemoteLookup[_remoteChainId];\n require(path.length != 0, \"LzApp: no trusted path record\");\n return path.slice(0, path.length - 20); // the last 20 bytes should be address(this)\n }\n\n function setPrecrime(address _precrime) external onlyOwner {\n precrime = _precrime;\n emit SetPrecrime(_precrime);\n }\n\n function setMinDstGas(\n uint16 _dstChainId,\n uint16 _packetType,\n uint _minGas\n ) external onlyOwner {\n minDstGasLookup[_dstChainId][_packetType] = _minGas;\n emit SetMinDstGas(_dstChainId, _packetType, _minGas);\n }\n\n // if the size is 0, it means default size limit\n function setPayloadSizeLimit(uint16 _dstChainId, uint _size) external onlyOwner {\n payloadSizeLimitLookup[_dstChainId] = _size;\n }\n\n //--------------------------- VIEW FUNCTION ----------------------------------------\n function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {\n bytes memory trustedSource = trustedRemoteLookup[_srcChainId];\n return keccak256(trustedSource) == keccak256(_srcAddress);\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/mocks/LZEndpointMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\npragma abicoder v2;\n\nimport \"../interfaces/ILayerZeroReceiver.sol\";\nimport \"../interfaces/ILayerZeroEndpoint.sol\";\nimport \"../libs/LzLib.sol\";\n\n/*\nlike a real LayerZero endpoint but can be mocked, which handle message transmission, verification, and receipt.\n- blocking: LayerZero provides ordered delivery of messages from a given sender to a destination chain.\n- non-reentrancy: endpoint has a non-reentrancy guard for both the send() and receive(), respectively.\n- adapter parameters: allows UAs to add arbitrary transaction params in the send() function, like airdrop on destination chain.\nunlike a real LayerZero endpoint, it is\n- no messaging library versioning\n- send() will short circuit to lzReceive()\n- no user application configuration\n*/\ncontract LZEndpointMock is ILayerZeroEndpoint {\n uint8 internal constant _NOT_ENTERED = 1;\n uint8 internal constant _ENTERED = 2;\n\n mapping(address => address) public lzEndpointLookup;\n\n uint16 public mockChainId;\n bool public nextMsgBlocked;\n\n // fee config\n RelayerFeeConfig public relayerFeeConfig;\n ProtocolFeeConfig public protocolFeeConfig;\n uint public oracleFee;\n bytes public defaultAdapterParams;\n\n // path = remote addrss + local address\n // inboundNonce = [srcChainId][path].\n mapping(uint16 => mapping(bytes => uint64)) public inboundNonce;\n //todo: this is a hack\n // outboundNonce = [dstChainId][srcAddress]\n mapping(uint16 => mapping(address => uint64)) public outboundNonce;\n // // outboundNonce = [dstChainId][path].\n // mapping(uint16 => mapping(bytes => uint64)) public outboundNonce;\n // storedPayload = [srcChainId][path]\n mapping(uint16 => mapping(bytes => StoredPayload)) public storedPayload;\n // msgToDeliver = [srcChainId][path]\n mapping(uint16 => mapping(bytes => QueuedPayload[])) public msgsToDeliver;\n\n // reentrancy guard\n uint8 internal _send_entered_state = 1;\n uint8 internal _receive_entered_state = 1;\n\n struct ProtocolFeeConfig {\n uint zroFee;\n uint nativeBP;\n }\n\n struct RelayerFeeConfig {\n uint128 dstPriceRatio; // 10^10\n uint128 dstGasPriceInWei;\n uint128 dstNativeAmtCap;\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n struct StoredPayload {\n uint64 payloadLength;\n address dstAddress;\n bytes32 payloadHash;\n }\n\n struct QueuedPayload {\n address dstAddress;\n uint64 nonce;\n bytes payload;\n }\n\n modifier sendNonReentrant() {\n require(_send_entered_state == _NOT_ENTERED, \"LayerZeroMock: no send reentrancy\");\n _send_entered_state = _ENTERED;\n _;\n _send_entered_state = _NOT_ENTERED;\n }\n\n modifier receiveNonReentrant() {\n require(_receive_entered_state == _NOT_ENTERED, \"LayerZeroMock: no receive reentrancy\");\n _receive_entered_state = _ENTERED;\n _;\n _receive_entered_state = _NOT_ENTERED;\n }\n\n event UaForceResumeReceive(uint16 chainId, bytes srcAddress);\n event PayloadCleared(uint16 srcChainId, bytes srcAddress, uint64 nonce, address dstAddress);\n event PayloadStored(uint16 srcChainId, bytes srcAddress, address dstAddress, uint64 nonce, bytes payload, bytes reason);\n event ValueTransferFailed(address indexed to, uint indexed quantity);\n\n constructor(uint16 _chainId) {\n mockChainId = _chainId;\n\n // init config\n relayerFeeConfig = RelayerFeeConfig({\n dstPriceRatio: 1e10, // 1:1, same chain, same native coin\n dstGasPriceInWei: 1e10,\n dstNativeAmtCap: 1e19,\n baseGas: 100,\n gasPerByte: 1\n });\n protocolFeeConfig = ProtocolFeeConfig({zroFee: 1e18, nativeBP: 1000}); // BP 0.1\n oracleFee = 1e16;\n defaultAdapterParams = LzLib.buildDefaultAdapterParams(200000);\n }\n\n // ------------------------------ ILayerZeroEndpoint Functions ------------------------------\n function send(\n uint16 _chainId,\n bytes memory _path,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams\n ) external payable override sendNonReentrant {\n require(_path.length == 40, \"LayerZeroMock: incorrect remote address size\"); // only support evm chains\n\n address dstAddr;\n assembly {\n dstAddr := mload(add(_path, 20))\n }\n\n address lzEndpoint = lzEndpointLookup[dstAddr];\n require(lzEndpoint != address(0), \"LayerZeroMock: destination LayerZero Endpoint not found\");\n\n // not handle zro token\n bytes memory adapterParams = _adapterParams.length > 0 ? _adapterParams : defaultAdapterParams;\n (uint nativeFee, ) = estimateFees(_chainId, msg.sender, _payload, _zroPaymentAddress != address(0x0), adapterParams);\n require(msg.value >= nativeFee, \"LayerZeroMock: not enough native for fees\");\n\n uint64 nonce = ++outboundNonce[_chainId][msg.sender];\n\n // refund if they send too much\n uint amount = msg.value - nativeFee;\n if (amount > 0) {\n (bool success, ) = _refundAddress.call{value: amount}(\"\");\n require(success, \"LayerZeroMock: failed to refund\");\n }\n\n // Mock the process of receiving msg on dst chain\n // Mock the relayer paying the dstNativeAddr the amount of extra native token\n (, uint extraGas, uint dstNativeAmt, address payable dstNativeAddr) = LzLib.decodeAdapterParams(adapterParams);\n if (dstNativeAmt > 0) {\n (bool success, ) = dstNativeAddr.call{value: dstNativeAmt}(\"\");\n if (!success) {\n emit ValueTransferFailed(dstNativeAddr, dstNativeAmt);\n }\n }\n\n bytes memory srcUaAddress = abi.encodePacked(msg.sender, dstAddr); // cast this address to bytes\n bytes memory payload = _payload;\n LZEndpointMock(lzEndpoint).receivePayload(mockChainId, srcUaAddress, dstAddr, nonce, extraGas, payload);\n }\n\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _path,\n address _dstAddress,\n uint64 _nonce,\n uint _gasLimit,\n bytes calldata _payload\n ) external override receiveNonReentrant {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n\n // assert and increment the nonce. no message shuffling\n require(_nonce == ++inboundNonce[_srcChainId][_path], \"LayerZeroMock: wrong nonce\");\n\n // queue the following msgs inside of a stack to simulate a successful send on src, but not fully delivered on dst\n if (sp.payloadHash != bytes32(0)) {\n QueuedPayload[] storage msgs = msgsToDeliver[_srcChainId][_path];\n QueuedPayload memory newMsg = QueuedPayload(_dstAddress, _nonce, _payload);\n\n // warning, might run into gas issues trying to forward through a bunch of queued msgs\n // shift all the msgs over so we can treat this like a fifo via array.pop()\n if (msgs.length > 0) {\n // extend the array\n msgs.push(newMsg);\n\n // shift all the indexes up for pop()\n for (uint i = 0; i < msgs.length - 1; i++) {\n msgs[i + 1] = msgs[i];\n }\n\n // put the newMsg at the bottom of the stack\n msgs[0] = newMsg;\n } else {\n msgs.push(newMsg);\n }\n } else if (nextMsgBlocked) {\n storedPayload[_srcChainId][_path] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));\n emit PayloadStored(_srcChainId, _path, _dstAddress, _nonce, _payload, bytes(\"\"));\n // ensure the next msgs that go through are no longer blocked\n nextMsgBlocked = false;\n } else {\n try ILayerZeroReceiver(_dstAddress).lzReceive{gas: _gasLimit}(_srcChainId, _path, _nonce, _payload) {} catch (bytes memory reason) {\n storedPayload[_srcChainId][_path] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));\n emit PayloadStored(_srcChainId, _path, _dstAddress, _nonce, _payload, reason);\n // ensure the next msgs that go through are no longer blocked\n nextMsgBlocked = false;\n }\n }\n }\n\n function getInboundNonce(uint16 _chainID, bytes calldata _path) external view override returns (uint64) {\n return inboundNonce[_chainID][_path];\n }\n\n function getOutboundNonce(uint16 _chainID, address _srcAddress) external view override returns (uint64) {\n return outboundNonce[_chainID][_srcAddress];\n }\n\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes memory _payload,\n bool _payInZRO,\n bytes memory _adapterParams\n ) public view override returns (uint nativeFee, uint zroFee) {\n bytes memory adapterParams = _adapterParams.length > 0 ? _adapterParams : defaultAdapterParams;\n\n // Relayer Fee\n uint relayerFee = _getRelayerFee(_dstChainId, 1, _userApplication, _payload.length, adapterParams);\n\n // LayerZero Fee\n uint protocolFee = _getProtocolFees(_payInZRO, relayerFee, oracleFee);\n _payInZRO ? zroFee = protocolFee : nativeFee = protocolFee;\n\n // return the sum of fees\n nativeFee = nativeFee + relayerFee + oracleFee;\n }\n\n function getChainId() external view override returns (uint16) {\n return mockChainId;\n }\n\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _path,\n bytes calldata _payload\n ) external override {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n require(sp.payloadHash != bytes32(0), \"LayerZeroMock: no stored payload\");\n require(_payload.length == sp.payloadLength && keccak256(_payload) == sp.payloadHash, \"LayerZeroMock: invalid payload\");\n\n address dstAddress = sp.dstAddress;\n // empty the storedPayload\n sp.payloadLength = 0;\n sp.dstAddress = address(0);\n sp.payloadHash = bytes32(0);\n\n uint64 nonce = inboundNonce[_srcChainId][_path];\n\n ILayerZeroReceiver(dstAddress).lzReceive(_srcChainId, _path, nonce, _payload);\n emit PayloadCleared(_srcChainId, _path, nonce, dstAddress);\n }\n\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _path) external view override returns (bool) {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n return sp.payloadHash != bytes32(0);\n }\n\n function getSendLibraryAddress(address) external view override returns (address) {\n return address(this);\n }\n\n function getReceiveLibraryAddress(address) external view override returns (address) {\n return address(this);\n }\n\n function isSendingPayload() external view override returns (bool) {\n return _send_entered_state == _ENTERED;\n }\n\n function isReceivingPayload() external view override returns (bool) {\n return _receive_entered_state == _ENTERED;\n }\n\n function getConfig(\n uint16, /*_version*/\n uint16, /*_chainId*/\n address, /*_ua*/\n uint /*_configType*/\n ) external pure override returns (bytes memory) {\n return \"\";\n }\n\n function getSendVersion(\n address /*_userApplication*/\n ) external pure override returns (uint16) {\n return 1;\n }\n\n function getReceiveVersion(\n address /*_userApplication*/\n ) external pure override returns (uint16) {\n return 1;\n }\n\n function setConfig(\n uint16, /*_version*/\n uint16, /*_chainId*/\n uint, /*_configType*/\n bytes memory /*_config*/\n ) external override {}\n\n function setSendVersion(\n uint16 /*version*/\n ) external override {}\n\n function setReceiveVersion(\n uint16 /*version*/\n ) external override {}\n\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _path) external override {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n // revert if no messages are cached. safeguard malicious UA behaviour\n require(sp.payloadHash != bytes32(0), \"LayerZeroMock: no stored payload\");\n require(sp.dstAddress == msg.sender, \"LayerZeroMock: invalid caller\");\n\n // empty the storedPayload\n sp.payloadLength = 0;\n sp.dstAddress = address(0);\n sp.payloadHash = bytes32(0);\n\n emit UaForceResumeReceive(_srcChainId, _path);\n\n // resume the receiving of msgs after we force clear the \"stuck\" msg\n _clearMsgQue(_srcChainId, _path);\n }\n\n // ------------------------------ Other Public/External Functions --------------------------------------------------\n\n function getLengthOfQueue(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint) {\n return msgsToDeliver[_srcChainId][_srcAddress].length;\n }\n\n // used to simulate messages received get stored as a payload\n function blockNextMsg() external {\n nextMsgBlocked = true;\n }\n\n function setDestLzEndpoint(address destAddr, address lzEndpointAddr) external {\n lzEndpointLookup[destAddr] = lzEndpointAddr;\n }\n\n function setRelayerPrice(\n uint128 _dstPriceRatio,\n uint128 _dstGasPriceInWei,\n uint128 _dstNativeAmtCap,\n uint64 _baseGas,\n uint64 _gasPerByte\n ) external {\n relayerFeeConfig.dstPriceRatio = _dstPriceRatio;\n relayerFeeConfig.dstGasPriceInWei = _dstGasPriceInWei;\n relayerFeeConfig.dstNativeAmtCap = _dstNativeAmtCap;\n relayerFeeConfig.baseGas = _baseGas;\n relayerFeeConfig.gasPerByte = _gasPerByte;\n }\n\n function setProtocolFee(uint _zroFee, uint _nativeBP) external {\n protocolFeeConfig.zroFee = _zroFee;\n protocolFeeConfig.nativeBP = _nativeBP;\n }\n\n function setOracleFee(uint _oracleFee) external {\n oracleFee = _oracleFee;\n }\n\n function setDefaultAdapterParams(bytes memory _adapterParams) external {\n defaultAdapterParams = _adapterParams;\n }\n\n // --------------------- Internal Functions ---------------------\n // simulates the relayer pushing through the rest of the msgs that got delayed due to the stored payload\n function _clearMsgQue(uint16 _srcChainId, bytes calldata _path) internal {\n QueuedPayload[] storage msgs = msgsToDeliver[_srcChainId][_path];\n\n // warning, might run into gas issues trying to forward through a bunch of queued msgs\n while (msgs.length > 0) {\n QueuedPayload memory payload = msgs[msgs.length - 1];\n ILayerZeroReceiver(payload.dstAddress).lzReceive(_srcChainId, _path, payload.nonce, payload.payload);\n msgs.pop();\n }\n }\n\n function _getProtocolFees(\n bool _payInZro,\n uint _relayerFee,\n uint _oracleFee\n ) internal view returns (uint) {\n if (_payInZro) {\n return protocolFeeConfig.zroFee;\n } else {\n return ((_relayerFee + _oracleFee) * protocolFeeConfig.nativeBP) / 10000;\n }\n }\n\n function _getRelayerFee(\n uint16, /* _dstChainId */\n uint16, /* _outboundProofType */\n address, /* _userApplication */\n uint _payloadSize,\n bytes memory _adapterParams\n ) internal view returns (uint) {\n (uint16 txType, uint extraGas, uint dstNativeAmt, ) = LzLib.decodeAdapterParams(_adapterParams);\n uint totalRemoteToken; // = baseGas + extraGas + requiredNativeAmount\n if (txType == 2) {\n require(relayerFeeConfig.dstNativeAmtCap >= dstNativeAmt, \"LayerZeroMock: dstNativeAmt too large \");\n totalRemoteToken += dstNativeAmt;\n }\n // remoteGasTotal = dstGasPriceInWei * (baseGas + extraGas)\n uint remoteGasTotal = relayerFeeConfig.dstGasPriceInWei * (relayerFeeConfig.baseGas + extraGas);\n totalRemoteToken += remoteGasTotal;\n\n // tokenConversionRate = dstPrice / localPrice\n // basePrice = totalRemoteToken * tokenConversionRate\n uint basePrice = (totalRemoteToken * relayerFeeConfig.dstPriceRatio) / 10**10;\n\n // pricePerByte = (dstGasPriceInWei * gasPerBytes) * tokenConversionRate\n uint pricePerByte = (relayerFeeConfig.dstGasPriceInWei * relayerFeeConfig.gasPerByte * relayerFeeConfig.dstPriceRatio) / 10**10;\n\n return basePrice + _payloadSize * pricePerByte;\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/NonblockingLzApp.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./LzApp.sol\";\nimport \"../libraries/ExcessivelySafeCall.sol\";\n\n/*\n * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel\n * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking\n * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)\n */\nabstract contract NonblockingLzApp is LzApp {\n using ExcessivelySafeCall for address;\n\n constructor(address _endpoint) LzApp(_endpoint) {}\n\n mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages;\n\n event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);\n event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);\n\n // overriding the virtual function in LzReceiver\n function _blockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual override {\n (bool success, bytes memory reason) = address(this).excessivelySafeCall(\n gasleft(),\n 150,\n abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload)\n );\n if (!success) {\n _storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason);\n }\n }\n\n function _storeFailedMessage(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload,\n bytes memory _reason\n ) internal virtual {\n failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);\n emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);\n }\n\n function nonblockingLzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public virtual {\n // only internal transaction\n require(_msgSender() == address(this), \"NonblockingLzApp: caller must be LzApp\");\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n //@notice override this function\n function _nonblockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual;\n\n function retryMessage(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public payable virtual {\n // assert there is message to retry\n bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];\n require(payloadHash != bytes32(0), \"NonblockingLzApp: no stored message\");\n require(keccak256(_payload) == payloadHash, \"NonblockingLzApp: invalid payload\");\n // clear the stored message\n failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0);\n // execute the message. revert if it fails again\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash);\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n function __Ownable2Step_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() external {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n _requireNotPaused();\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n _requirePaused();\n _;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Throws if the contract is paused.\n */\n function _requireNotPaused() internal view virtual {\n require(!paused(), \"Pausable: paused\");\n }\n\n /**\n * @dev Throws if the contract is not paused.\n */\n function _requirePaused() internal view virtual {\n require(paused(), \"Pausable: not paused\");\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" + }, + "@venusprotocol/solidity-utilities/contracts/validators.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Thrown if the supplied value is 0 where it is not allowed\nerror ZeroValueNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n}\n\n/// @notice Checks if the provided value is nonzero, reverts otherwise\n/// @param value_ Value to check\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\nfunction ensureNonzeroValue(uint256 value_) pure {\n if (value_ == 0) {\n revert ZeroValueNotAllowed();\n }\n}\n" + }, + "contracts/Cross-chain/BaseOmnichainControllerDest.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npragma solidity 0.8.25;\n\nimport { NonblockingLzApp } from \"@layerzerolabs/solidity-examples/contracts/lzApp/NonblockingLzApp.sol\";\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title BaseOmnichainControllerDest\n * @author Venus\n * @dev This contract is the base for the Omnichain controller destination contract\n * It provides functionality related to daily command limits and pausability\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\nabstract contract BaseOmnichainControllerDest is NonblockingLzApp, Pausable {\n /**\n * @notice Maximum daily limit for receiving commands from Binance chain\n */\n uint256 public maxDailyReceiveLimit;\n\n /**\n * @notice Total received commands within the last 24-hour window from Binance chain\n */\n uint256 public last24HourCommandsReceived;\n\n /**\n * @notice Timestamp when the last 24-hour window started from Binance chain\n */\n uint256 public last24HourReceiveWindowStart;\n\n /**\n * @notice Emitted when the maximum daily limit for receiving command from Binance chain is modified\n */\n event SetMaxDailyReceiveLimit(uint256 oldMaxLimit, uint256 newMaxLimit);\n\n constructor(address endpoint_) NonblockingLzApp(endpoint_) {\n ensureNonzeroAddress(endpoint_);\n }\n\n /**\n * @notice Sets the maximum daily limit for receiving commands\n * @param limit_ Number of commands\n * @custom:access Only Owner\n * @custom:event Emits SetMaxDailyReceiveLimit with old and new limit\n */\n function setMaxDailyReceiveLimit(uint256 limit_) external onlyOwner {\n emit SetMaxDailyReceiveLimit(maxDailyReceiveLimit, limit_);\n maxDailyReceiveLimit = limit_;\n }\n\n /**\n * @notice Triggers the paused state of the controller\n * @custom:access Only owner\n */\n function pause() external onlyOwner {\n _pause();\n }\n\n /**\n * @notice Triggers the resume state of the controller\n * @custom:access Only owner\n */\n function unpause() external onlyOwner {\n _unpause();\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishappening\n */\n function renounceOwnership() public override {}\n\n /**\n * @notice Check eligibility to receive commands\n * @param noOfCommands_ Number of commands to be received\n */\n function _isEligibleToReceive(uint256 noOfCommands_) internal {\n uint256 currentBlockTimestamp = block.timestamp;\n\n // Load values for the 24-hour window checks for receiving\n uint256 receivedInWindow = last24HourCommandsReceived;\n\n // Check if the time window has changed (more than 24 hours have passed)\n if (currentBlockTimestamp - last24HourReceiveWindowStart > 1 days) {\n receivedInWindow = noOfCommands_;\n last24HourReceiveWindowStart = currentBlockTimestamp;\n } else {\n receivedInWindow += noOfCommands_;\n }\n\n // Revert if the received amount exceeds the daily limit\n require(receivedInWindow <= maxDailyReceiveLimit, \"Daily Transaction Limit Exceeded\");\n\n // Update the received amount for the 24-hour window\n last24HourCommandsReceived = receivedInWindow;\n }\n}\n" + }, + "contracts/Cross-chain/BaseOmnichainControllerSrc.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npragma solidity 0.8.25;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { IAccessControlManagerV8 } from \"./../Governance/IAccessControlManagerV8.sol\";\n\n/**\n * @title BaseOmnichainControllerSrc\n * @dev This contract is the base for the Omnichain controller source contracts.\n * It provides functionality related to daily command limits and pausability.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract BaseOmnichainControllerSrc is Ownable, Pausable {\n /**\n * @notice ACM (Access Control Manager) contract address\n */\n address public accessControlManager;\n\n /**\n * @notice Maximum daily limit for commands from the local chain\n */\n mapping(uint16 => uint256) public chainIdToMaxDailyLimit;\n\n /**\n * @notice Total commands transferred within the last 24-hour window from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourCommandsSent;\n\n /**\n * @notice Timestamp when the last 24-hour window started from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourWindowStart;\n /**\n * @notice Timestamp when the last proposal sent from the local chain to dest chain\n */\n mapping(uint16 => uint256) public chainIdToLastProposalSentTimestamp;\n\n /**\n * @notice Emitted when the maximum daily limit of commands from the local chain is modified\n */\n event SetMaxDailyLimit(uint16 indexed chainId, uint256 oldMaxLimit, uint256 newMaxLimit);\n /*\n * @notice Emitted when the address of ACM is updated\n */\n event NewAccessControlManager(address indexed oldAccessControlManager, address indexed newAccessControlManager);\n\n constructor(address accessControlManager_) {\n ensureNonzeroAddress(accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Sets the limit of daily (24 Hour) command amount\n * @param chainId_ Destination chain id\n * @param limit_ Number of commands\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetMaxDailyLimit with old and new limit and its corresponding chain id\n */\n function setMaxDailyLimit(uint16 chainId_, uint256 limit_) external {\n _ensureAllowed(\"setMaxDailyLimit(uint16,uint256)\");\n emit SetMaxDailyLimit(chainId_, chainIdToMaxDailyLimit[chainId_], limit_);\n chainIdToMaxDailyLimit[chainId_] = limit_;\n }\n\n /**\n * @notice Triggers the paused state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function pause() external {\n _ensureAllowed(\"pause()\");\n _pause();\n }\n\n /**\n * @notice Triggers the resume state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function unpause() external {\n _ensureAllowed(\"unpause()\");\n _unpause();\n }\n\n /**\n * @notice Sets the address of Access Control Manager (ACM)\n * @param accessControlManager_ The new address of the Access Control Manager\n * @custom:access Only owner\n * @custom:event Emits NewAccessControlManager with old and new access control manager addresses\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n ensureNonzeroAddress(accessControlManager_);\n emit NewAccessControlManager(accessControlManager, accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishap\n */\n function renounceOwnership() public override {}\n\n /**\n * @notice Check eligibility to send commands\n * @param dstChainId_ Destination chain id\n * @param noOfCommands_ Number of commands to send\n */\n function _isEligibleToSend(uint16 dstChainId_, uint256 noOfCommands_) internal {\n // Load values for the 24-hour window checks\n uint256 currentBlockTimestamp = block.timestamp;\n uint256 lastDayWindowStart = chainIdToLast24HourWindowStart[dstChainId_];\n uint256 commandsSentInWindow = chainIdToLast24HourCommandsSent[dstChainId_];\n uint256 maxDailyLimit = chainIdToMaxDailyLimit[dstChainId_];\n uint256 lastProposalSentTimestamp = chainIdToLastProposalSentTimestamp[dstChainId_];\n\n // Check if the time window has changed (more than 24 hours have passed)\n if (currentBlockTimestamp - lastDayWindowStart > 1 days) {\n commandsSentInWindow = noOfCommands_;\n chainIdToLast24HourWindowStart[dstChainId_] = currentBlockTimestamp;\n } else {\n commandsSentInWindow += noOfCommands_;\n }\n\n // Revert if the amount exceeds the daily limit\n require(commandsSentInWindow <= maxDailyLimit, \"Daily Transaction Limit Exceeded\");\n // Revert if the last proposal is already sent in current block i.e multiple proposals cannot be sent within the same block.timestamp\n require(lastProposalSentTimestamp != currentBlockTimestamp, \"Multiple bridging in a proposal\");\n\n // Update the amount for the 24-hour window\n chainIdToLast24HourCommandsSent[dstChainId_] = commandsSentInWindow;\n // Update the last sent proposal timestamp\n chainIdToLastProposalSentTimestamp[dstChainId_] = currentBlockTimestamp;\n }\n\n /**\n * @notice Ensure that the caller has permission to execute a specific function\n * @param functionSig_ Function signature to be checked for permission\n */\n function _ensureAllowed(string memory functionSig_) internal view {\n require(\n IAccessControlManagerV8(accessControlManager).isAllowedToCall(msg.sender, functionSig_),\n \"access denied\"\n );\n }\n}\n" + }, + "contracts/Cross-chain/interfaces/IOmnichainGovernanceExecutor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\ninterface IOmnichainGovernanceExecutor {\n /**\n * @notice Transfers ownership of the contract to the specified address\n * @param addr The address to which ownership will be transferred\n */\n function transferOwnership(address addr) external;\n\n /**\n * @notice Sets the source message sender address\n * @param srcChainId_ The LayerZero id of a source chain\n * @param srcAddress_ The address of the contract on the source chain\n */\n function setTrustedRemoteAddress(uint16 srcChainId_, bytes calldata srcAddress_) external;\n}\n" + }, + "contracts/Cross-chain/interfaces/ITimelock.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/**\n * @title ITimelock\n * @author Venus\n * @dev Interface for Timelock contract\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\ninterface ITimelock {\n /**\n * @notice Delay period for the transaction queue\n */\n function delay() external view returns (uint256);\n\n /**\n * @notice Required period to execute a proposal transaction\n */\n function GRACE_PERIOD() external view returns (uint256);\n\n /**\n * @notice Method for accepting a proposed admin\n */\n function acceptAdmin() external;\n\n /**\n * @notice Method to propose a new admin authorized to call timelock functions. This should be the Governor Contract.\n */\n function setPendingAdmin(address pendingAdmin) external;\n\n /**\n * @notice Show mapping of queued transactions\n * @param hash Transaction hash\n */\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n /**\n * @notice Called for each action when queuing a proposal\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Hash of the queued transaction\n */\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n /**\n * @notice Called to cancel a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n */\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n /**\n * @notice Called to execute a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Result of function call\n */\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/Cross-chain/OmnichainExecutorOwner.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { AccessControlledV8 } from \"../Governance/AccessControlledV8.sol\";\nimport { IOmnichainGovernanceExecutor } from \"./interfaces/IOmnichainGovernanceExecutor.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title OmnichainExecutorOwner\n * @author Venus\n * @notice OmnichainProposalSender contract acts as a governance and access control mechanism,\n * allowing owner to upsert signature of OmnichainGovernanceExecutor contract,\n * also contains function to transfer the ownership of contract as well.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract OmnichainExecutorOwner is AccessControlledV8 {\n /**\n * @custom:oz-upgrades-unsafe-allow state-variable-immutable\n */\n IOmnichainGovernanceExecutor public immutable OMNICHAIN_GOVERNANCE_EXECUTOR;\n\n /**\n * @notice Stores function signature corresponding to their 4 bytes hash value\n */\n mapping(bytes4 => string) public functionRegistry;\n\n /**\n * @notice Event emitted when function registry updated\n */\n event FunctionRegistryChanged(string indexed signature, bool active);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address omnichainGovernanceExecutor_) {\n require(omnichainGovernanceExecutor_ != address(0), \"Address must not be zero\");\n OMNICHAIN_GOVERNANCE_EXECUTOR = IOmnichainGovernanceExecutor(omnichainGovernanceExecutor_);\n _disableInitializers();\n }\n\n /**\n * @notice Initialize the contract\n * @param accessControlManager_ Address of access control manager\n */\n function initialize(address accessControlManager_) external initializer {\n require(accessControlManager_ != address(0), \"Address must not be zero\");\n __AccessControlled_init(accessControlManager_);\n }\n\n /**\n * @notice Sets the source message sender address\n * @param srcChainId_ The LayerZero id of a source chain\n * @param srcAddress_ The address of the contract on the source chain\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetTrustedRemoteAddress with source chain Id and source address\n */\n function setTrustedRemoteAddress(uint16 srcChainId_, bytes calldata srcAddress_) external {\n _checkAccessAllowed(\"setTrustedRemoteAddress(uint16,bytes)\");\n require(srcChainId_ != 0, \"ChainId must not be zero\");\n ensureNonzeroAddress(address(uint160(bytes20(srcAddress_))));\n require(srcAddress_.length == 20, \"Source address must be 20 bytes long\");\n OMNICHAIN_GOVERNANCE_EXECUTOR.setTrustedRemoteAddress(srcChainId_, srcAddress_);\n }\n\n /**\n * @notice Invoked when called function does not exist in the contract\n * @param data_ Calldata containing the encoded function call\n * @return Result of function call\n * @custom:access Controlled by Access Control Manager\n */\n fallback(bytes calldata data_) external returns (bytes memory) {\n string memory fun = functionRegistry[msg.sig];\n require(bytes(fun).length != 0, \"Function not found\");\n _checkAccessAllowed(fun);\n (bool ok, bytes memory res) = address(OMNICHAIN_GOVERNANCE_EXECUTOR).call(data_);\n require(ok, \"call failed\");\n return res;\n }\n\n /**\n * @notice A registry of functions that are allowed to be executed from proposals\n * @param signatures_ Function signature to be added or removed\n * @param active_ bool value, should be true to add function\n * @custom:access Only owner\n */\n function upsertSignature(string[] calldata signatures_, bool[] calldata active_) external onlyOwner {\n uint256 signatureLength = signatures_.length;\n require(signatureLength == active_.length, \"Input arrays must have the same length\");\n for (uint256 i; i < signatureLength; ++i) {\n bytes4 sigHash = bytes4(keccak256(bytes(signatures_[i])));\n bytes memory signature = bytes(functionRegistry[sigHash]);\n if (active_[i] && signature.length == 0) {\n functionRegistry[sigHash] = signatures_[i];\n emit FunctionRegistryChanged(signatures_[i], true);\n } else if (!active_[i] && signature.length != 0) {\n delete functionRegistry[sigHash];\n emit FunctionRegistryChanged(signatures_[i], false);\n }\n }\n }\n\n /**\n * @notice This function transfer the ownership of the executor from this contract to new owner\n * @param newOwner_ New owner of the governanceExecutor\n * @custom:access Controlled by AccessControlManager\n */\n\n function transferBridgeOwnership(address newOwner_) external {\n _checkAccessAllowed(\"transferBridgeOwnership(address)\");\n require(newOwner_ != address(0), \"Address must not be zero\");\n OMNICHAIN_GOVERNANCE_EXECUTOR.transferOwnership(newOwner_);\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishappening\n */\n function renounceOwnership() public virtual override {}\n}\n" + }, + "contracts/Cross-chain/OmnichainGovernanceExecutor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.25;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { BytesLib } from \"@layerzerolabs/solidity-examples/contracts/libraries/BytesLib.sol\";\nimport { ExcessivelySafeCall } from \"@layerzerolabs/solidity-examples/contracts/libraries/ExcessivelySafeCall.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { BaseOmnichainControllerDest } from \"./BaseOmnichainControllerDest.sol\";\nimport { ITimelock } from \"./interfaces/ITimelock.sol\";\n\n/**\n * @title OmnichainGovernanceExecutor\n * @notice Executes the proposal transactions sent from the main chain\n * @dev The owner of this contract controls LayerZero configuration. When used in production the owner will be OmnichainExecutor\n * This implementation is non-blocking, meaning the failed messages will not block the future messages from the source.\n * For the blocking behavior, derive the contract from LzApp.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\ncontract OmnichainGovernanceExecutor is ReentrancyGuard, BaseOmnichainControllerDest {\n using BytesLib for bytes;\n using ExcessivelySafeCall for address;\n\n enum ProposalType {\n NORMAL,\n FASTTRACK,\n CRITICAL\n }\n\n struct Proposal {\n /** Unique id for looking up a proposal */\n uint256 id;\n /** The timestamp that the proposal will be available for execution, set once the vote succeeds */\n uint256 eta;\n /** The ordered list of target addresses for calls to be made */\n address[] targets;\n /** The ordered list of values (i.e. msg.value) to be passed to the calls to be made */\n uint256[] values;\n /** The ordered list of function signatures to be called */\n string[] signatures;\n /** The ordered list of calldata to be passed to each call */\n bytes[] calldatas;\n /** Flag marking whether the proposal has been canceled */\n bool canceled;\n /** Flag marking whether the proposal has been executed */\n bool executed;\n /** The type of the proposal */\n uint8 proposalType;\n }\n /*\n * @notice Possible states that a proposal may be in\n */\n enum ProposalState {\n Canceled,\n Queued,\n Executed\n }\n\n /**\n * @notice A privileged role that can cancel any proposal\n */\n address public guardian;\n\n /**\n * @notice Stores BNB chain layerzero endpoint id\n */\n uint16 public srcChainId;\n\n /**\n * @notice Last proposal count received\n */\n uint256 public lastProposalReceived;\n\n /**\n * @notice The official record of all proposals ever proposed\n */\n mapping(uint256 => Proposal) public proposals;\n\n /**\n * @notice Mapping containing Timelock addresses for each proposal type\n */\n mapping(uint256 => ITimelock) public proposalTimelocks;\n\n /**\n * @notice Represents queue state of proposal\n */\n mapping(uint256 => bool) public queued;\n\n /**\n * @notice Emitted when proposal is received\n */\n event ProposalReceived(\n uint256 indexed proposalId,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint8 proposalType\n );\n\n /**\n * @notice Emitted when proposal is queued\n */\n event ProposalQueued(uint256 indexed id, uint256 eta);\n\n /**\n * Emitted when proposal executed\n */\n event ProposalExecuted(uint256 indexed id);\n\n /**\n * @notice Emitted when proposal failed\n */\n event ReceivePayloadFailed(uint16 indexed srcChainId, bytes indexed srcAddress, uint64 nonce, bytes reason);\n\n /**\n * @notice Emitted when proposal is canceled\n */\n event ProposalCanceled(uint256 indexed id);\n\n /**\n * @notice Emitted when timelock added\n */\n event TimelockAdded(uint8 routeType, address indexed oldTimelock, address indexed newTimelock);\n\n /**\n * @notice Emitted when source layerzero endpoint id is updated\n */\n event SetSrcChainId(uint16 indexed oldSrcChainId, uint16 indexed newSrcChainId);\n\n /**\n * @notice Emitted when new guardian address is set\n */\n event NewGuardian(address indexed oldGuardian, address indexed newGuardian);\n\n /**\n * @notice Emitted when pending admin of Timelock is updated\n */\n event SetTimelockPendingAdmin(address, uint8);\n\n /**\n * @notice Thrown when proposal ID is invalid\n */\n error InvalidProposalId();\n\n constructor(address endpoint_, address guardian_, uint16 srcChainId_) BaseOmnichainControllerDest(endpoint_) {\n ensureNonzeroAddress(guardian_);\n guardian = guardian_;\n srcChainId = srcChainId_;\n }\n\n /**\n * @notice Update source layerzero endpoint id\n * @param srcChainId_ The new source chain id to be set\n * @custom:event Emit SetSrcChainId with old and new source id\n * @custom:access Only owner\n */\n function setSrcChainId(uint16 srcChainId_) external onlyOwner {\n emit SetSrcChainId(srcChainId, srcChainId_);\n srcChainId = srcChainId_;\n }\n\n /**\n * @notice Sets the new executor guardian\n * @param newGuardian The address of the new guardian\n * @custom:access Must be call by guardian or owner\n * @custom:event Emit NewGuardian with old and new guardian address\n */\n function setGuardian(address newGuardian) external {\n require(\n msg.sender == guardian || msg.sender == owner(),\n \"OmnichainGovernanceExecutor::setGuardian: owner or guardian only\"\n );\n ensureNonzeroAddress(newGuardian);\n emit NewGuardian(guardian, newGuardian);\n guardian = newGuardian;\n }\n\n /**\n * @notice Add timelocks to the ProposalTimelocks mapping\n * @param timelocks_ Array of addresses of all 3 timelocks\n * @custom:access Only owner\n * @custom:event Emits TimelockAdded with old and new timelock and route type\n */\n function addTimelocks(ITimelock[] memory timelocks_) external onlyOwner {\n uint8 length = uint8(type(ProposalType).max) + 1;\n require(\n timelocks_.length == length,\n \"OmnichainGovernanceExecutor::addTimelocks:number of timelocks should match the number of governance routes\"\n );\n for (uint8 i; i < length; ++i) {\n ensureNonzeroAddress(address(timelocks_[i]));\n emit TimelockAdded(i, address(proposalTimelocks[i]), address(timelocks_[i]));\n proposalTimelocks[i] = timelocks_[i];\n }\n }\n\n /**\n * @notice Executes a queued proposal if eta has passed\n * @param proposalId_ Id of proposal that is to be executed\n * @custom:event Emits ProposalExecuted with proposal id of executed proposal\n */\n function execute(uint256 proposalId_) external nonReentrant {\n require(\n state(proposalId_) == ProposalState.Queued,\n \"OmnichainGovernanceExecutor::execute: proposal can only be executed if it is queued\"\n );\n\n Proposal storage proposal = proposals[proposalId_];\n proposal.executed = true;\n ITimelock timelock = proposalTimelocks[proposal.proposalType];\n uint256 eta = proposal.eta;\n uint256 length = proposal.targets.length;\n\n emit ProposalExecuted(proposalId_);\n\n for (uint256 i; i < length; ++i) {\n timelock.executeTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n delete queued[proposalId_];\n }\n\n /**\n * @notice Cancels a proposal only if sender is the guardian and proposal is not executed\n * @param proposalId_ Id of proposal that is to be canceled\n * @custom:access Sender must be the guardian\n * @custom:event Emits ProposalCanceled with proposal id of the canceled proposal\n */\n function cancel(uint256 proposalId_) external {\n require(\n state(proposalId_) == ProposalState.Queued,\n \"OmnichainGovernanceExecutor::cancel: proposal should be queued and not executed\"\n );\n Proposal storage proposal = proposals[proposalId_];\n require(msg.sender == guardian, \"OmnichainGovernanceExecutor::cancel: sender must be guardian\");\n\n proposal.canceled = true;\n ITimelock timelock = proposalTimelocks[proposal.proposalType];\n uint256 eta = proposal.eta;\n uint256 length = proposal.targets.length;\n\n emit ProposalCanceled(proposalId_);\n\n for (uint256 i; i < length; ++i) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n delete queued[proposalId_];\n }\n\n /**\n * @notice Sets the new pending admin of the Timelock\n * @param pendingAdmin_ Address of new pending admin\n * @param proposalType_ Type of proposal\n * @custom:access Only owner\n * @custom:event Emits SetTimelockPendingAdmin with new pending admin and proposal type\n */\n function setTimelockPendingAdmin(address pendingAdmin_, uint8 proposalType_) external onlyOwner {\n uint8 proposalTypeLength = uint8(type(ProposalType).max) + 1;\n require(\n proposalType_ < proposalTypeLength,\n \"OmnichainGovernanceExecutor::setTimelockPendingAdmin: invalid proposal type\"\n );\n\n proposalTimelocks[proposalType_].setPendingAdmin(pendingAdmin_);\n emit SetTimelockPendingAdmin(pendingAdmin_, proposalType_);\n }\n\n /**\n * @notice Resends a previously failed message\n * @param srcChainId_ Source chain Id\n * @param srcAddress_ Source address => local app address + remote app address\n * @param nonce_ Nonce to identify failed message\n * @param payload_ The payload of the message to be retried\n * @custom:access Only owner\n */\n function retryMessage(\n uint16 srcChainId_,\n bytes calldata srcAddress_,\n uint64 nonce_,\n bytes calldata payload_\n ) public payable override onlyOwner nonReentrant {\n require(\n keccak256(trustedRemoteLookup[srcChainId_]) == keccak256(srcAddress_),\n \"OmnichainGovernanceExecutor::retryMessage: not a trusted remote\"\n );\n super.retryMessage(srcChainId_, srcAddress_, nonce_, payload_);\n }\n\n /**\n * @notice Gets the state of a proposal\n * @param proposalId_ The id of the proposal\n * @return Proposal state\n */\n function state(uint256 proposalId_) public view returns (ProposalState) {\n Proposal storage proposal = proposals[proposalId_];\n if (proposal.canceled) {\n return ProposalState.Canceled;\n } else if (proposal.executed) {\n return ProposalState.Executed;\n } else if (queued[proposalId_]) {\n // queued only when proposal is received\n return ProposalState.Queued;\n } else {\n revert InvalidProposalId();\n }\n }\n\n /**\n * @notice Process blocking LayerZero receive request\n * @param srcChainId_ Source chain Id\n * @param srcAddress_ Source address from which payload is received\n * @param nonce_ Nonce associated with the payload to prevent replay attacks\n * @param payload_ Encoded payload containing proposal information\n * @custom:event Emit ReceivePayloadFailed if call fails\n */\n function _blockingLzReceive(\n uint16 srcChainId_,\n bytes memory srcAddress_,\n uint64 nonce_,\n bytes memory payload_\n ) internal virtual override {\n require(srcChainId_ == srcChainId, \"OmnichainGovernanceExecutor::_blockingLzReceive: invalid source chain id\");\n bytes32 hashedPayload = keccak256(payload_);\n bytes memory callData = abi.encodeCall(this.nonblockingLzReceive, (srcChainId_, srcAddress_, nonce_, payload_));\n\n (bool success, bytes memory reason) = address(this).excessivelySafeCall(gasleft() - 30000, 150, callData);\n // try-catch all errors/exceptions\n if (!success) {\n failedMessages[srcChainId_][srcAddress_][nonce_] = hashedPayload;\n emit ReceivePayloadFailed(srcChainId_, srcAddress_, nonce_, reason); // Retrieve payload from the src side tx if needed to clear\n }\n }\n\n /**\n * @notice Process non blocking LayerZero receive request\n * @param payload_ Encoded payload containing proposal information\n * @custom:event Emit ProposalReceived\n */\n function _nonblockingLzReceive(\n uint16,\n bytes memory,\n uint64,\n bytes memory payload_\n ) internal virtual override whenNotPaused {\n (bytes memory payload, uint256 pId) = abi.decode(payload_, (bytes, uint256));\n (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n uint8 pType\n ) = abi.decode(payload, (address[], uint256[], string[], bytes[], uint8));\n require(proposals[pId].id == 0, \"OmnichainGovernanceExecutor::_nonblockingLzReceive: duplicate proposal\");\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"OmnichainGovernanceExecutor::_nonblockingLzReceive: proposal function information arity mismatch\"\n );\n require(\n pType < uint8(type(ProposalType).max) + 1,\n \"OmnichainGovernanceExecutor::_nonblockingLzReceive: invalid proposal type\"\n );\n _isEligibleToReceive(targets.length);\n\n Proposal memory newProposal = Proposal({\n id: pId,\n eta: 0,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas,\n canceled: false,\n executed: false,\n proposalType: pType\n });\n\n proposals[pId] = newProposal;\n lastProposalReceived = pId;\n\n emit ProposalReceived(newProposal.id, targets, values, signatures, calldatas, pType);\n _queue(pId);\n }\n\n /**\n * @notice Queue proposal for execution\n * @param proposalId_ Proposal to be queued\n * @custom:event Emit ProposalQueued with proposal id and eta\n */\n function _queue(uint256 proposalId_) internal {\n Proposal storage proposal = proposals[proposalId_];\n uint256 eta = block.timestamp + proposalTimelocks[proposal.proposalType].delay();\n\n proposal.eta = eta;\n queued[proposalId_] = true;\n uint8 proposalType = proposal.proposalType;\n uint256 length = proposal.targets.length;\n emit ProposalQueued(proposalId_, eta);\n\n for (uint256 i; i < length; ++i) {\n _queueOrRevertInternal(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta,\n proposalType\n );\n }\n }\n\n /**\n * @notice Check for unique proposal\n * @param target_ Address of the contract with the method to be called\n * @param value_ Native token amount sent with the transaction\n * @param signature_ Signature of the function to be called\n * @param data_ Arguments to be passed to the function when called\n * @param eta_ Timestamp after which the transaction can be executed\n * @param proposalType_ Type of proposal\n */\n function _queueOrRevertInternal(\n address target_,\n uint256 value_,\n string memory signature_,\n bytes memory data_,\n uint256 eta_,\n uint8 proposalType_\n ) internal {\n require(\n !proposalTimelocks[proposalType_].queuedTransactions(\n keccak256(abi.encode(target_, value_, signature_, data_, eta_))\n ),\n \"OmnichainGovernanceExecutor::queueOrRevertInternal: identical proposal action already queued at eta\"\n );\n\n proposalTimelocks[proposalType_].queueTransaction(target_, value_, signature_, data_, eta_);\n }\n}\n" + }, + "contracts/Cross-chain/OmnichainProposalSender.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.25;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { ILayerZeroEndpoint } from \"@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { BaseOmnichainControllerSrc } from \"./BaseOmnichainControllerSrc.sol\";\n\n/**\n * @title OmnichainProposalSender\n * @author Venus\n * @notice OmnichainProposalSender contract builds upon the functionality of its parent contract , BaseOmnichainControllerSrc\n * It sends a proposal's data to remote chains for execution after the proposal passes on the main chain\n * when used with GovernorBravo, the owner of this contract must be set to the Timelock contract\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract OmnichainProposalSender is ReentrancyGuard, BaseOmnichainControllerSrc {\n /**\n * @notice Stores the total number of remote proposals\n */\n uint256 public proposalCount;\n\n /**\n * @notice Execution hashes of failed messages\n * @dev [proposalId] -> [executionHash]\n */\n mapping(uint256 => bytes32) public storedExecutionHashes;\n\n /**\n * @notice LayerZero endpoint for sending messages to remote chains\n */\n ILayerZeroEndpoint public immutable LZ_ENDPOINT;\n\n /**\n * @notice Specifies the allowed path for sending messages (remote chainId => remote app address + local app address)\n */\n mapping(uint16 => bytes) public trustedRemoteLookup;\n\n /**\n * @notice Emitted when a remote message receiver is set for the remote chain\n */\n event SetTrustedRemoteAddress(uint16 indexed remoteChainId, bytes oldRemoteAddress, bytes newRemoteAddress);\n\n /**\n * @notice Event emitted when trusted remote sets to empty\n */\n event TrustedRemoteRemoved(uint16 indexed chainId);\n\n /**\n * @notice Emitted when a proposal execution request is sent to the remote chain\n */\n event ExecuteRemoteProposal(uint16 indexed remoteChainId, uint256 proposalId, bytes payload);\n\n /**\n * @notice Emitted when a previously failed message is successfully sent to the remote chain\n */\n event ClearPayload(uint256 indexed proposalId, bytes32 executionHash);\n\n /**\n * @notice Emitted when an execution hash of a failed message is saved\n */\n event StorePayload(\n uint256 indexed proposalId,\n uint16 indexed remoteChainId,\n bytes payload,\n bytes adapterParams,\n uint256 value,\n bytes reason\n );\n /**\n * @notice Emitted while fallback withdraw\n */\n event FallbackWithdraw(address indexed receiver, uint256 value);\n\n constructor(\n ILayerZeroEndpoint lzEndpoint_,\n address accessControlManager_\n ) BaseOmnichainControllerSrc(accessControlManager_) {\n ensureNonzeroAddress(address(lzEndpoint_));\n LZ_ENDPOINT = lzEndpoint_;\n }\n\n /**\n * @notice Estimates LayerZero fees for cross-chain message delivery to the remote chain\n * @dev The estimated fees are the minimum required; it's recommended to increase the fees amount when sending a message. The unused amount will be refunded\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param payload_ The payload to be sent to the remote chain. It's computed as follows:\n * payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param useZro_ Bool that indicates whether to pay in ZRO tokens or not\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @return nativeFee The amount of fee in the native gas token (e.g. ETH)\n * @return zroFee The amount of fee in ZRO token\n */\n function estimateFees(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bool useZro_,\n bytes calldata adapterParams_\n ) external view returns (uint256, uint256) {\n return LZ_ENDPOINT.estimateFees(remoteChainId_, address(this), payload_, useZro_, adapterParams_);\n }\n\n /**\n * @notice Remove trusted remote from storage\n * @param remoteChainId_ The chain's id corresponds to setting the trusted remote to empty\n * @custom:access Controlled by Access Control Manager\n * @custom:event Emit TrustedRemoteRemoved with remote chain id\n */\n function removeTrustedRemote(uint16 remoteChainId_) external {\n _ensureAllowed(\"removeTrustedRemote(uint16)\");\n require(trustedRemoteLookup[remoteChainId_].length != 0, \"OmnichainProposalSender: trusted remote not found\");\n delete trustedRemoteLookup[remoteChainId_];\n emit TrustedRemoteRemoved(remoteChainId_);\n }\n\n /**\n * @notice Sends a message to execute a remote proposal\n * @dev Stores the hash of the execution parameters if sending fails (e.g., due to insufficient fees)\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(targets, values, signatures, calldatas, proposalType)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction. This must be either address(this) or tx.origin\n * @custom:event Emits ExecuteRemoteProposal with remote chain id, proposal ID and payload on success\n * @custom:event Emits StorePayload with last stored payload proposal ID ,remote chain id , payload, adapter params , values and reason for failure\n * @custom:access Controlled by Access Control Manager\n */\n function execute(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_\n ) external payable whenNotPaused {\n _ensureAllowed(\"execute(uint16,bytes,bytes,address)\");\n\n // A zero value will result in a failed message; therefore, a positive value is required to send a message across the chain.\n require(msg.value > 0, \"OmnichainProposalSender: value cannot be zero\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n _validateProposal(remoteChainId_, payload_);\n uint256 _pId = ++proposalCount;\n bytes memory payload = abi.encode(payload_, _pId);\n\n try\n LZ_ENDPOINT.send{ value: msg.value }(\n remoteChainId_,\n trustedRemote,\n payload,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n )\n {\n emit ExecuteRemoteProposal(remoteChainId_, _pId, payload);\n } catch (bytes memory reason) {\n storedExecutionHashes[_pId] = keccak256(abi.encode(remoteChainId_, payload, adapterParams_, msg.value));\n emit StorePayload(_pId, remoteChainId_, payload, adapterParams_, msg.value, reason);\n }\n }\n\n /**\n * @notice Resends a previously failed message\n * @dev Allows providing more fees if needed. The extra fees will be refunded to the caller\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction.\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:access Controlled by Access Control Manager\n */\n function retryExecute(\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_,\n uint256 originalValue_\n ) external payable whenNotPaused nonReentrant {\n _ensureAllowed(\"retryExecute(uint256,uint16,bytes,bytes,address,uint256)\");\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n (bytes memory payload, ) = abi.decode(payload_, (bytes, uint256));\n _validateProposal(remoteChainId_, payload);\n\n require(\n keccak256(abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_)) == hash,\n \"OmnichainProposalSender: invalid execution params\"\n );\n\n delete storedExecutionHashes[pId_];\n\n emit ClearPayload(pId_, hash);\n\n LZ_ENDPOINT.send{ value: originalValue_ + msg.value }(\n remoteChainId_,\n trustedRemote,\n payload_,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n );\n }\n\n /**\n * @notice Clear previously failed message\n * @param to_ Address of the receiver\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:access Only owner\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:event Emits FallbackWithdraw with receiver and amount\n */\n function fallbackWithdraw(\n address to_,\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n uint256 originalValue_\n ) external onlyOwner nonReentrant {\n ensureNonzeroAddress(to_);\n require(originalValue_ > 0, \"OmnichainProposalSender: invalid native amount\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n\n bytes memory execution = abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_);\n require(keccak256(execution) == hash, \"OmnichainProposalSender: invalid execution params\");\n\n delete storedExecutionHashes[pId_];\n\n emit FallbackWithdraw(to_, originalValue_);\n emit ClearPayload(pId_, hash);\n\n // Transfer the native to the `to_` address\n (bool sent, ) = to_.call{ value: originalValue_ }(\"\");\n require(sent, \"Call failed\");\n }\n\n /**\n * @notice Sets the remote message receiver address\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param newRemoteAddress_ The address of the contract on the remote chain to receive messages sent by this contract\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetTrustedRemoteAddress with remote chain Id and remote address\n */\n function setTrustedRemoteAddress(uint16 remoteChainId_, bytes calldata newRemoteAddress_) external {\n _ensureAllowed(\"setTrustedRemoteAddress(uint16,bytes)\");\n require(remoteChainId_ != 0, \"OmnichainProposalSender: chainId must not be zero\");\n ensureNonzeroAddress(address(uint160(bytes20(newRemoteAddress_))));\n require(newRemoteAddress_.length == 20, \"OmnichainProposalSender: remote address must be 20 bytes long\");\n bytes memory oldRemoteAddress = trustedRemoteLookup[remoteChainId_];\n trustedRemoteLookup[remoteChainId_] = abi.encodePacked(newRemoteAddress_, address(this));\n emit SetTrustedRemoteAddress(remoteChainId_, oldRemoteAddress, trustedRemoteLookup[remoteChainId_]);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId for the pending config change\n * @param configType_ The type of configuration. Every messaging library has its own convention\n * @param config_ The configuration in bytes. It can encode arbitrary content\n * @custom:access Controlled by AccessControlManager\n */\n function setConfig(uint16 version_, uint16 chainId_, uint256 configType_, bytes calldata config_) external {\n _ensureAllowed(\"setConfig(uint16,uint16,uint256,bytes)\");\n LZ_ENDPOINT.setConfig(version_, chainId_, configType_, config_);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ New messaging library version\n * @custom:access Controlled by AccessControlManager\n */\n function setSendVersion(uint16 version_) external {\n _ensureAllowed(\"setSendVersion(uint16)\");\n LZ_ENDPOINT.setSendVersion(version_);\n }\n\n /**\n * @notice Gets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId\n * @param configType_ Type of configuration. Every messaging library has its own convention\n */\n function getConfig(uint16 version_, uint16 chainId_, uint256 configType_) external view returns (bytes memory) {\n return LZ_ENDPOINT.getConfig(version_, chainId_, address(this), configType_);\n }\n\n function _validateProposal(uint16 remoteChainId_, bytes memory payload_) internal {\n (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n\n ) = abi.decode(payload_, (address[], uint[], string[], bytes[], uint8));\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"OmnichainProposalSender: proposal function information arity mismatch\"\n );\n _isEligibleToSend(remoteChainId_, targets.length);\n }\n}\n" + }, + "contracts/Governance/AccessControlledV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlledV8\n * @author Venus\n * @notice This contract is helper between access control manager and actual contract. This contract further inherited by other contract (using solidity 0.8.13)\n * to integrate access controlled mechanism. It provides initialise methods and verifying access methods.\n */\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n /// @notice Access control manager contract\n IAccessControlManagerV8 private _accessControlManager;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when access control manager contract address is changed\n event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n /// @notice Thrown when the action is prohibited by AccessControlManager\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Sets the address of AccessControlManager\n * @dev Admin function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n * @custom:event Emits NewAccessControlManager event\n * @custom:access Only Governance\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Returns the address of the access control manager contract\n */\n function accessControlManager() external view returns (IAccessControlManagerV8) {\n return _accessControlManager;\n }\n\n /**\n * @dev Internal function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n */\n function _setAccessControlManager(address accessControlManager_) internal {\n require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n address oldAccessControlManager = address(_accessControlManager);\n _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n }\n\n /**\n * @notice Reverts if the call is not allowed by AccessControlManager\n * @param signature Method signature\n */\n function _checkAccessAllowed(string memory signature) internal view {\n bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n }\n}\n" + }, + "contracts/Governance/AccessControlManager.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlManager\n * @author Venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl extending it in a way to standartize access control within Venus Smart Contract Ecosystem.\n * @notice Access control plays a crucial role in the Venus governance model. It is used to restrict functions so that they can only be called from one\n * account or list of accounts (EOA or Contract Accounts).\n *\n * The implementation of `AccessControlManager`(https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/AccessControlManager.sol)\n * inherits the [Open Zeppelin AccessControl](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol)\n * contract as a base for role management logic. There are two role types: admin and granular permissions.\n * \n * ## Granular Roles\n * \n * Granular roles are built by hashing the contract address and its function signature. For example, given contract `Foo` with function `Foo.bar()` which\n * is guarded by ACM, calling `giveRolePermission` for account B do the following:\n * \n * 1. Compute `keccak256(contractFooAddress,functionSignatureBar)`\n * 1. Add the computed role to the roles of account B\n * 1. Account B now can call `ContractFoo.bar()`\n * \n * ## Admin Roles\n * \n * Admin roles allow for an address to call a function signature on any contract guarded by the `AccessControlManager`. This is particularly useful for\n * contracts created by factories.\n * \n * For Admin roles a null address is hashed in place of the contract address (`keccak256(0x0000000000000000000000000000000000000000,functionSignatureBar)`.\n * \n * In the previous example, giving account B the admin role, account B will have permissions to call the `bar()` function on any contract that is guarded by\n * ACM, not only contract A.\n * \n * ## Protocol Integration\n * \n * All restricted functions in Venus Protocol use a hook to ACM in order to check if the caller has the right permission to call the guarded function.\n * `AccessControlledV5` and `AccessControlledV8` abstract contract makes this integration easier. They call ACM's external method\n * `isAllowedToCall(address caller, string functionSig)`. Here is an example of how `setCollateralFactor` function in `Comptroller` is integrated with ACM:\n\n```\n contract Comptroller is [...] AccessControlledV8 {\n [...]\n function setCollateralFactor(VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external {\n _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n [...]\n }\n }\n```\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n /// @notice Emitted when an account is given a permission to a certain contract function\n /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n /// can call any contract function with this signature\n event PermissionGranted(address account, address contractAddress, string functionSig);\n\n /// @notice Emitted when an account is revoked a permission to a certain contract function\n event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n constructor() {\n // Grant the contract deployer the default admin role: it will be able\n // to grant and revoke any roles\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n /**\n * @notice Gives a function call permission to one single account\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * @param contractAddress address of contract for which call permissions will be granted\n * @dev if contractAddress is zero address, the account can access the specified function\n * on **any** contract managed by this ACL\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @param accountToPermit account that will be given access to the contract function\n * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n */\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n grantRole(role, accountToPermit);\n emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n }\n\n /**\n * @notice Revokes an account's permission to a particular function call\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * \t\tMay emit a {RoleRevoked} event.\n * @param contractAddress address of contract for which call permissions will be revoked\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n */\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n revokeRole(role, accountToRevoke);\n emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n * @param account for which call permissions will be checked\n * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n *\n */\n function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n if (hasRole(role, account)) {\n return true;\n } else {\n role = keccak256(abi.encodePacked(address(0), functionSig));\n return hasRole(role, account);\n }\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n * @param account for which call permissions will be checked against\n * @param contractAddress address of the restricted contract\n * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n */\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n return hasRole(role, account);\n }\n}\n" + }, + "contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + }, + "contracts/Governance/TimelockV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title TimelockV8\n * @author Venus\n * @notice The Timelock contract using solidity V8.\n * This contract also differs from the original timelock because it has a virtual function to get minimum delays\n * and allow test deployments to override the value.\n */\ncontract TimelockV8 {\n /// @notice Required period to execute a proposal transaction\n uint256 private constant DEFAULT_GRACE_PERIOD = 14 days;\n\n /// @notice Minimum amount of time a proposal transaction must be queued\n uint256 private constant DEFAULT_MINIMUM_DELAY = 1 hours;\n\n /// @notice Maximum amount of time a proposal transaction must be queued\n uint256 private constant DEFAULT_MAXIMUM_DELAY = 30 days;\n\n /// @notice Timelock admin authorized to queue and execute transactions\n address public admin;\n\n /// @notice Account proposed as the next admin\n address public pendingAdmin;\n\n /// @notice Period for a proposal transaction to be queued\n uint256 public delay;\n\n /// @notice Mapping of queued transactions\n mapping(bytes32 => bool) public queuedTransactions;\n\n /// @notice Event emitted when a new admin is accepted\n event NewAdmin(address indexed oldAdmin, address indexed newAdmin);\n\n /// @notice Event emitted when a new admin is proposed\n event NewPendingAdmin(address indexed newPendingAdmin);\n\n /// @notice Event emitted when a new delay is proposed\n event NewDelay(uint256 indexed oldDelay, uint256 indexed newDelay);\n\n /// @notice Event emitted when a proposal transaction has been cancelled\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /// @notice Event emitted when a proposal transaction has been executed\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /// @notice Event emitted when a proposal transaction has been queued\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n constructor(address admin_, uint256 delay_) {\n require(delay_ >= MINIMUM_DELAY(), \"Timelock::constructor: Delay must exceed minimum delay.\");\n require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n ensureNonzeroAddress(admin_);\n\n admin = admin_;\n delay = delay_;\n }\n\n fallback() external payable {}\n\n /**\n * @notice Setter for the transaction queue delay\n * @param delay_ The new delay period for the transaction queue\n * @custom:access Sender must be Timelock itself\n * @custom:event Emit NewDelay with old and new delay\n */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY(), \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n emit NewDelay(delay, delay_);\n delay = delay_;\n }\n\n /**\n * @notice Return grace period\n * @return The duration of the grace period, specified as a uint256 value.\n */\n function GRACE_PERIOD() public view virtual returns (uint256) {\n return DEFAULT_GRACE_PERIOD;\n }\n\n /**\n * @notice Return required minimum delay\n * @return Minimum delay\n */\n function MINIMUM_DELAY() public view virtual returns (uint256) {\n return DEFAULT_MINIMUM_DELAY;\n }\n\n /**\n * @notice Return required maximum delay\n * @return Maximum delay\n */\n function MAXIMUM_DELAY() public view virtual returns (uint256) {\n return DEFAULT_MAXIMUM_DELAY;\n }\n\n /**\n * @notice Method for accepting a proposed admin\n * @custom:access Sender must be pending admin\n * @custom:event Emit NewAdmin with old and new admin\n */\n function acceptAdmin() public {\n require(msg.sender == pendingAdmin, \"Timelock::acceptAdmin: Call must come from pendingAdmin.\");\n emit NewAdmin(admin, msg.sender);\n admin = msg.sender;\n pendingAdmin = address(0);\n }\n\n /**\n * @notice Method to propose a new admin authorized to call timelock functions. This should be the Governor Contract\n * @param pendingAdmin_ Address of the proposed admin\n * @custom:access Sender must be Timelock contract itself or admin\n * @custom:event Emit NewPendingAdmin with new pending admin\n */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this) || msg.sender == admin,\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n ensureNonzeroAddress(pendingAdmin_);\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Called for each action when queuing a proposal\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Hash of the queued transaction\n * @custom:access Sender must be admin\n * @custom:event Emit QueueTransaction\n */\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp() + delay,\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(!queuedTransactions[txHash], \"Timelock::queueTransaction: transaction already queued.\");\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Called to cancel a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @custom:access Sender must be admin\n * @custom:event Emit CancelTransaction\n */\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(queuedTransactions[txHash], \"Timelock::cancelTransaction: transaction is not queued yet.\");\n delete (queuedTransactions[txHash]);\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Called to execute a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Result of function call\n * @custom:access Sender must be admin\n * @custom:event Emit ExecuteTransaction\n */\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(queuedTransactions[txHash], \"Timelock::executeTransaction: Transaction hasn't been queued.\");\n require(getBlockTimestamp() >= eta, \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\");\n require(getBlockTimestamp() <= eta + GRACE_PERIOD(), \"Timelock::executeTransaction: Transaction is stale.\");\n\n delete (queuedTransactions[txHash]);\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call{ value: value }(callData);\n require(success, \"Timelock::executeTransaction: Transaction execution reverted.\");\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice Returns the current block timestamp\n * @return The current block timestamp\n */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/test/MockAccessTest.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"../Governance/AccessControlledV8.sol\";\nimport \"@layerzerolabs/solidity-examples/contracts/lzApp/mocks/LZEndpointMock.sol\";\n\ncontract MockAccessTest is AccessControlledV8 {\n /**\n * @param accessControlManager Access control manager contract address\n */\n function initialize(address accessControlManager) external initializer {\n __AccessControlled_init_unchained(accessControlManager);\n }\n}\n" + }, + "contracts/test/MockXVSVault.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\ncontract MockXVSVault {\n /* solhint-disable no-unused-vars */\n function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96) {\n /* solhint-enable no-unused-vars */\n return 0;\n }\n}\n" + }, + "contracts/test/TestTimelockV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { TimelockV8 } from \"../Governance/TimelockV8.sol\";\n\ncontract TestTimelockV8 is TimelockV8 {\n constructor(address admin_, uint256 delay_) public TimelockV8(admin_, delay_) {}\n\n function GRACE_PERIOD() public view override returns (uint256) {\n return 1 hours;\n }\n\n function MINIMUM_DELAY() public view override returns (uint256) {\n return 1;\n }\n\n function MAXIMUM_DELAY() public view override returns (uint256) {\n return 1 hours;\n }\n}\n" + }, + "contracts/Utils/ACMCommandsAggregator.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IAccessControlManagerV8 } from \"../Governance/IAccessControlManagerV8.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title ACMCommandsAggregator\n * @author Venus\n * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\n */\ncontract ACMCommandsAggregator {\n /*\n * @notice Struct to store permission details\n */\n struct Permission {\n /*\n * @notice Address of the contract\n */\n address contractAddress;\n /*\n * @notice Function signature\n */\n string functionSig;\n /*\n * @notice Address of the account\n */\n address account;\n }\n\n /**\n * @notice Access control manager contract\n */\n IAccessControlManagerV8 public immutable ACM;\n\n /*\n * @notice 2D array to store grant permissions in batches\n */\n Permission[][] public grantPermissions;\n\n /*\n * @notice 2D array to store revoke permissions in batches\n */\n Permission[][] public revokePermissions;\n\n /*\n * @notice Event emitted when grant permissions are added\n */\n event GrantPermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when revoke permissions are added\n */\n event RevokePermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when grant permissions are executed\n */\n event GrantPermissionsExecuted(uint256 index);\n\n /*\n * @notice Event emitted when revoke permissions are executed\n */\n event RevokePermissionsExecuted(uint256 index);\n\n /*\n * @notice Error to be thrown when permissions are empty\n */\n error EmptyPermissions();\n\n /*\n * @notice Constructor to set the access control manager\n * @param _acm Address of the access control manager\n */\n constructor(IAccessControlManagerV8 _acm) {\n ensureNonzeroAddress(address(_acm));\n ACM = _acm;\n }\n\n /*\n * @notice Function to add grant permissions\n * @param _permissions Array of permissions\n * @custom:event Emits GrantPermissionsAdded event\n */\n function addGrantPermissions(Permission[] memory _permissions) external {\n if (_permissions.length == 0) {\n revert EmptyPermissions();\n }\n\n uint256 index = grantPermissions.length;\n grantPermissions.push();\n\n for (uint256 i; i < _permissions.length; ++i) {\n grantPermissions[index].push(\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n );\n }\n\n emit GrantPermissionsAdded(index);\n }\n\n /*\n * @notice Function to add revoke permissions\n * @param _permissions Array of permissions\n * @custom:event Emits RevokePermissionsAdded event\n */\n function addRevokePermissions(Permission[] memory _permissions) external {\n if (_permissions.length == 0) {\n revert EmptyPermissions();\n }\n\n uint256 index = revokePermissions.length;\n revokePermissions.push();\n\n for (uint256 i; i < _permissions.length; ++i) {\n revokePermissions[index].push(\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n );\n }\n\n emit RevokePermissionsAdded(index);\n }\n\n /*\n * @notice Function to execute grant permissions\n * @param index Index of the permissions array\n * @custom:event Emits GrantPermissionsExecuted event\n */\n function executeGrantPermissions(uint256 index) external {\n uint256 length = grantPermissions[index].length;\n for (uint256 i; i < length; ++i) {\n Permission memory permission = grantPermissions[index][i];\n ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n }\n\n emit GrantPermissionsExecuted(index);\n }\n\n /*\n * @notice Function to execute revoke permissions\n * @param index Index of the permissions array\n * @custom:event Emits RevokePermissionsExecuted event\n */\n function executeRevokePermissions(uint256 index) external {\n uint256 length = revokePermissions[index].length;\n for (uint256 i; i < length; ++i) {\n Permission memory permission = revokePermissions[index][i];\n ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n }\n\n emit RevokePermissionsExecuted(index);\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 10000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/opbnbtestnet_addresses.json b/deployments/opbnbtestnet_addresses.json index 8221b546..7a513e89 100644 --- a/deployments/opbnbtestnet_addresses.json +++ b/deployments/opbnbtestnet_addresses.json @@ -2,6 +2,7 @@ "name": "opbnbtestnet", "chainId": "5611", "addresses": { + "ACMCommandsAggregator": "0xbDd501dB1B0D6aab299CE69ef5B86C8578947AD0", "AccessControlManager": "0x049f77F7046266d27C3bC96376f53C17Ef09c986", "CriticalTimelock": "0xBd06aCDEF38230F4EdA0c6FD392905Ad463e42E3", "DefaultProxyAdmin": "0xB1281ADC816fba7df64B798D7A0BC4bd2a6d42f4", diff --git a/deployments/sepolia.json b/deployments/sepolia.json index 273e9b5a..bf38fe5a 100644 --- a/deployments/sepolia.json +++ b/deployments/sepolia.json @@ -2,6 +2,251 @@ "name": "sepolia", "chainId": "11155111", "contracts": { + "ACMCommandsAggregator": { + "address": "0x0653830c55035d678e1287b2d4550519fd263d0e", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "_acm", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantPermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "revokePermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ] + }, "AccessControlManager": { "address": "0xbf705C00578d43B6147ab4eaE04DBBEd1ccCdc96", "abi": [ diff --git a/deployments/sepolia/ACMCommandsAggregator.json b/deployments/sepolia/ACMCommandsAggregator.json new file mode 100644 index 00000000..8d7b647b --- /dev/null +++ b/deployments/sepolia/ACMCommandsAggregator.json @@ -0,0 +1,365 @@ +{ + "address": "0x0653830c55035d678e1287b2d4550519fd263d0e", + "abi": [ + { + "inputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "_acm", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EmptyPermissions", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddressNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "GrantPermissionsExecuted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsAdded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "RevokePermissionsExecuted", + "type": "event" + }, + { + "inputs": [], + "name": "ACM", + "outputs": [ + { + "internalType": "contract IAccessControlManagerV8", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "internalType": "struct ACMCommandsAggregator.Permission[]", + "name": "_permissions", + "type": "tuple[]" + } + ], + "name": "addRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeGrantPermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "index", + "type": "uint256" + } + ], + "name": "executeRevokePermissions", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "grantPermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "revokePermissions", + "outputs": [ + { + "internalType": "address", + "name": "contractAddress", + "type": "address" + }, + { + "internalType": "string", + "name": "functionSig", + "type": "string" + }, + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } + ], + "transactionHash": "0x0ac213f0e86734b3f657112afd1b186461d3d74ef78775005f00c41511e54aea", + "receipt": { + "to": null, + "from": "0x464779c41c5f1be598853c1f87bcc7087ea75f28", + "contractAddress": "0x0653830c55035d678e1287b2d4550519fd263d0e", + "transactionIndex": "0x9", + "gasUsed": "0xe4e9d", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x6565c0d252370e1abf6118a5d1ad370f519f723a739cffbecbc8b97aae37412f", + "transactionHash": "0x8abec38cf29f4c4a3d8e651685435c7634a5ab037a11f28103722121d0437a6e", + "logs": [], + "blockNumber": "0x67da37", + "cumulativeGasUsed": "0x14b661", + "status": "0x1" + }, + "args": ["0xbf705C00578d43B6147ab4eaE04DBBEd1ccCdc96"], + "numDeployments": 4, + "solcInputHash": "8462bae4a0ff7e7203ecab090cdf091c", + "metadata": "{\"compiler\":{\"version\":\"0.8.25+commit.b61c2a91\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"contract IAccessControlManagerV8\",\"name\":\"_acm\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"EmptyPermissions\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ZeroAddressNotAllowed\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"GrantPermissionsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"GrantPermissionsExecuted\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"RevokePermissionsAdded\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"RevokePermissionsExecuted\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ACM\",\"outputs\":[{\"internalType\":\"contract IAccessControlManagerV8\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"internalType\":\"struct ACMCommandsAggregator.Permission[]\",\"name\":\"_permissions\",\"type\":\"tuple[]\"}],\"name\":\"addGrantPermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"internalType\":\"struct ACMCommandsAggregator.Permission[]\",\"name\":\"_permissions\",\"type\":\"tuple[]\"}],\"name\":\"addRevokePermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"executeGrantPermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"executeRevokePermissions\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"grantPermissions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"revokePermissions\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"contractAddress\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"functionSig\",\"type\":\"string\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Venus\",\"kind\":\"dev\",\"methods\":{},\"title\":\"ACMCommandsAggregator\",\"version\":1},\"userdoc\":{\"errors\":{\"ZeroAddressNotAllowed()\":[{\"notice\":\"Thrown if the supplied address is a zero address where it is not allowed\"}]},\"kind\":\"user\",\"methods\":{\"ACM()\":{\"notice\":\"Access control manager contract\"}},\"notice\":\"This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/Utils/ACMCommandsAggregator.sol\":\"ACMCommandsAggregator\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/IAccessControl.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev External interface of AccessControl declared to support ERC165 detection.\\n */\\ninterface IAccessControl {\\n /**\\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\\n *\\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\\n * {RoleAdminChanged} not being emitted signaling this.\\n *\\n * _Available since v3.1._\\n */\\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\\n\\n /**\\n * @dev Emitted when `account` is granted `role`.\\n *\\n * `sender` is the account that originated the contract call, an admin role\\n * bearer except when using {AccessControl-_setupRole}.\\n */\\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Emitted when `account` is revoked `role`.\\n *\\n * `sender` is the account that originated the contract call:\\n * - if using `revokeRole`, it is the admin role bearer\\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\\n */\\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\\n\\n /**\\n * @dev Returns `true` if `account` has been granted `role`.\\n */\\n function hasRole(bytes32 role, address account) external view returns (bool);\\n\\n /**\\n * @dev Returns the admin role that controls `role`. See {grantRole} and\\n * {revokeRole}.\\n *\\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\\n */\\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\\n\\n /**\\n * @dev Grants `role` to `account`.\\n *\\n * If `account` had not been already granted `role`, emits a {RoleGranted}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function grantRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from `account`.\\n *\\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\\n *\\n * Requirements:\\n *\\n * - the caller must have ``role``'s admin role.\\n */\\n function revokeRole(bytes32 role, address account) external;\\n\\n /**\\n * @dev Revokes `role` from the calling account.\\n *\\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\\n * purpose is to provide a mechanism for accounts to lose their privileges\\n * if they are compromised (such as when a trusted device is misplaced).\\n *\\n * If the calling account had been granted `role`, emits a {RoleRevoked}\\n * event.\\n *\\n * Requirements:\\n *\\n * - the caller must be `account`.\\n */\\n function renounceRole(bytes32 role, address account) external;\\n}\\n\",\"keccak256\":\"0x59ce320a585d7e1f163cd70390a0ef2ff9cec832e2aa544293a00692465a7a57\",\"license\":\"MIT\"},\"@venusprotocol/solidity-utilities/contracts/validators.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\\nerror ZeroAddressNotAllowed();\\n\\n/// @notice Thrown if the supplied value is 0 where it is not allowed\\nerror ZeroValueNotAllowed();\\n\\n/// @notice Checks if the provided address is nonzero, reverts otherwise\\n/// @param address_ Address to check\\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\\nfunction ensureNonzeroAddress(address address_) pure {\\n if (address_ == address(0)) {\\n revert ZeroAddressNotAllowed();\\n }\\n}\\n\\n/// @notice Checks if the provided value is nonzero, reverts otherwise\\n/// @param value_ Value to check\\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\\nfunction ensureNonzeroValue(uint256 value_) pure {\\n if (value_ == 0) {\\n revert ZeroValueNotAllowed();\\n }\\n}\\n\",\"keccak256\":\"0xdb88e14d50dd21889ca3329d755673d022c47e8da005b6a545c7f69c2c4b7b86\",\"license\":\"BSD-3-Clause\"},\"contracts/Governance/IAccessControlManagerV8.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity ^0.8.25;\\n\\nimport \\\"@openzeppelin/contracts/access/IAccessControl.sol\\\";\\n\\n/**\\n * @title IAccessControlManagerV8\\n * @author Venus\\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\\n */\\ninterface IAccessControlManagerV8 is IAccessControl {\\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\\n\\n function revokeCallPermission(\\n address contractAddress,\\n string calldata functionSig,\\n address accountToRevoke\\n ) external;\\n\\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\\n\\n function hasPermission(\\n address account,\\n address contractAddress,\\n string calldata functionSig\\n ) external view returns (bool);\\n}\\n\",\"keccak256\":\"0xaa29b098440d0b3a131c5ecdf25ce548790c1b5ac7bf9b5c0264b6af6f7a1e0b\",\"license\":\"BSD-3-Clause\"},\"contracts/Utils/ACMCommandsAggregator.sol\":{\"content\":\"// SPDX-License-Identifier: BSD-3-Clause\\npragma solidity 0.8.25;\\n\\nimport { IAccessControlManagerV8 } from \\\"../Governance/IAccessControlManagerV8.sol\\\";\\nimport { ensureNonzeroAddress } from \\\"@venusprotocol/solidity-utilities/contracts/validators.sol\\\";\\n\\n/**\\n * @title ACMCommandsAggregator\\n * @author Venus\\n * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\\n */\\ncontract ACMCommandsAggregator {\\n /*\\n * @notice Struct to store permission details\\n */\\n struct Permission {\\n /*\\n * @notice Address of the contract\\n */\\n address contractAddress;\\n /*\\n * @notice Function signature\\n */\\n string functionSig;\\n /*\\n * @notice Address of the account\\n */\\n address account;\\n }\\n\\n /**\\n * @notice Access control manager contract\\n */\\n IAccessControlManagerV8 public immutable ACM;\\n\\n /*\\n * @notice 2D array to store grant permissions in batches\\n */\\n Permission[][] public grantPermissions;\\n\\n /*\\n * @notice 2D array to store revoke permissions in batches\\n */\\n Permission[][] public revokePermissions;\\n\\n /*\\n * @notice Event emitted when grant permissions are added\\n */\\n event GrantPermissionsAdded(uint256 index);\\n\\n /*\\n * @notice Event emitted when revoke permissions are added\\n */\\n event RevokePermissionsAdded(uint256 index);\\n\\n /*\\n * @notice Event emitted when grant permissions are executed\\n */\\n event GrantPermissionsExecuted(uint256 index);\\n\\n /*\\n * @notice Event emitted when revoke permissions are executed\\n */\\n event RevokePermissionsExecuted(uint256 index);\\n\\n /*\\n * @notice Error to be thrown when permissions are empty\\n */\\n error EmptyPermissions();\\n\\n /*\\n * @notice Constructor to set the access control manager\\n * @param _acm Address of the access control manager\\n */\\n constructor(IAccessControlManagerV8 _acm) {\\n ensureNonzeroAddress(address(_acm));\\n ACM = _acm;\\n }\\n\\n /*\\n * @notice Function to add grant permissions\\n * @param _permissions Array of permissions\\n * @custom:event Emits GrantPermissionsAdded event\\n */\\n function addGrantPermissions(Permission[] memory _permissions) external {\\n if (_permissions.length == 0) {\\n revert EmptyPermissions();\\n }\\n\\n uint256 index = grantPermissions.length;\\n grantPermissions.push();\\n\\n for (uint256 i; i < _permissions.length; ++i) {\\n grantPermissions[index].push(\\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\\n );\\n }\\n\\n emit GrantPermissionsAdded(index);\\n }\\n\\n /*\\n * @notice Function to add revoke permissions\\n * @param _permissions Array of permissions\\n * @custom:event Emits RevokePermissionsAdded event\\n */\\n function addRevokePermissions(Permission[] memory _permissions) external {\\n if (_permissions.length == 0) {\\n revert EmptyPermissions();\\n }\\n\\n uint256 index = revokePermissions.length;\\n revokePermissions.push();\\n\\n for (uint256 i; i < _permissions.length; ++i) {\\n revokePermissions[index].push(\\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\\n );\\n }\\n\\n emit RevokePermissionsAdded(index);\\n }\\n\\n /*\\n * @notice Function to execute grant permissions\\n * @param index Index of the permissions array\\n * @custom:event Emits GrantPermissionsExecuted event\\n */\\n function executeGrantPermissions(uint256 index) external {\\n uint256 length = grantPermissions[index].length;\\n for (uint256 i; i < length; ++i) {\\n Permission memory permission = grantPermissions[index][i];\\n ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account);\\n }\\n\\n emit GrantPermissionsExecuted(index);\\n }\\n\\n /*\\n * @notice Function to execute revoke permissions\\n * @param index Index of the permissions array\\n * @custom:event Emits RevokePermissionsExecuted event\\n */\\n function executeRevokePermissions(uint256 index) external {\\n uint256 length = revokePermissions[index].length;\\n for (uint256 i; i < length; ++i) {\\n Permission memory permission = revokePermissions[index][i];\\n ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account);\\n }\\n\\n emit RevokePermissionsExecuted(index);\\n }\\n}\\n\",\"keccak256\":\"0xe642b8f0e0fedc74d31196197bc7d78b43b44eab556c07ec74d6b75ccf8d0f8c\",\"license\":\"BSD-3-Clause\"}},\"version\":1}", + "bytecode": "0x60a0604052348015600f57600080fd5b506040516110c73803806110c7833981016040819052602c91606c565b6033816043565b6001600160a01b0316608052609a565b6001600160a01b0381166069576040516342bcdf7f60e11b815260040160405180910390fd5b50565b600060208284031215607d57600080fd5b81516001600160a01b0381168114609357600080fd5b9392505050565b6080516110046100c360003960008181610100015281816102de0152610a0101526110046000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c80639d6c76b81161005b5780639d6c76b8146100d5578063de46a235146100e8578063f9b80da1146100fb578063ff1575e11461014757600080fd5b806322473d8c14610082578063514aab87146100975780635666a5ea146100c2575b600080fd5b610095610090366004610ab8565b61015a565b005b6100aa6100a5366004610ad1565b61038d565b6040516100b993929190610af3565b60405180910390f35b6100956100d0366004610c59565b610492565b6100956100e3366004610c59565b610689565b6100956100f6366004610ab8565b61087f565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b9565b6100aa610155366004610ad1565b610aa8565b60006001828154811061016f5761016f610de1565b600091825260208220015491505b818110156103545760006001848154811061019a5761019a610de1565b9060005260206000200182815481106101b5576101b5610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161020290610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461022e90610e10565b801561027b5780601f106102505761010080835404028352916020019161027b565b820191906000526020600020905b81548152906001019060200180831161025e57829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f545f7a320000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363545f7a329361031693909291600401610af3565b600060405180830381600087803b15801561033057600080fd5b505af1158015610344573d6000803e3d6000fd5b505050505080600101905061017d565b506040518281527f1382323d6618527d8b03daa05db815f0490966e8b80679fe5ad3d868f84e1a71906020015b60405180910390a15050565b6000828154811061039d57600080fd5b9060005260206000200181815481106103b557600080fd5b60009182526020909120600390910201805460018201805473ffffffffffffffffffffffffffffffffffffffff90921694509192506103f390610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461041f90610e10565b801561046c5780601f106104415761010080835404028352916020019161046c565b820191906000526020600020905b81548152906001019060200180831161044f57829003601f168201915b5050506002909301549192505073ffffffffffffffffffffffffffffffffffffffff1683565b80516000036104cd576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805480820182556000918252905b825181101561065857600182815481106104f9576104f9610de1565b90600052602060002001604051806060016040528085848151811061052057610520610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061055957610559610de1565b602002602001015160200151815260200185848151811061057c5761057c610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906106019082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016104dd565b506040518181527f75922591bf2cec980645dc4a32bb7d5e8da9a15fda86dacf06f8402cecd1478f90602001610381565b80516000036106c4576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054600181018255818052905b825181101561084e57600082815481106106ef576106ef610de1565b90600052602060002001604051806060016040528085848151811061071657610716610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061074f5761074f610de1565b602002602001015160200151815260200185848151811061077257610772610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906107f79082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016106d3565b506040518181527ff8ca6ea7cc31be8572501c37ef5e9e8298be717fb881e0b1ca785aecc4d25e9f90602001610381565b600080828154811061089357610893610de1565b600091825260208220015491505b81811015610a775760008084815481106108bd576108bd610de1565b9060005260206000200182815481106108d8576108d8610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161092590610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461095190610e10565b801561099e5780601f106109735761010080835404028352916020019161099e565b820191906000526020600020905b81548152906001019060200180831161098157829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f584f6b600000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363584f6b6093610a3993909291600401610af3565b600060405180830381600087803b158015610a5357600080fd5b505af1158015610a67573d6000803e3d6000fd5b50505050508060010190506108a1565b506040518281527f01a805f459381af632ecab72ec192c3f9a4c72d26be089026ffd6636d82de98890602001610381565b6001828154811061039d57600080fd5b600060208284031215610aca57600080fd5b5035919050565b60008060408385031215610ae457600080fd5b50508035926020909101359150565b600073ffffffffffffffffffffffffffffffffffffffff8086168352602060606020850152855180606086015260005b81811015610b3f57878101830151868201608001528201610b23565b5060006080828701015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010193505050808416604084015250949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610bdb57610bdb610b89565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c2857610c28610b89565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c5457600080fd5b919050565b60006020808385031215610c6c57600080fd5b823567ffffffffffffffff80821115610c8457600080fd5b818501915085601f830112610c9857600080fd5b813581811115610caa57610caa610b89565b8060051b610cb9858201610be1565b9182528381018501918581019089841115610cd357600080fd5b86860192505b83831015610dd457823585811115610cf057600080fd5b86017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06060828d0382011215610d265760008081fd5b610d2e610bb8565b610d398a8401610c30565b815260408084013589811115610d4f5760008081fd5b8401603f81018f13610d615760008081fd5b8b8101358a811115610d7557610d75610b89565b610d858d86601f84011601610be1565b94508085528f83828401011115610d9c5760008081fd5b808383018e87013760008d82870101525050828b830152610dbf60608501610c30565b90820152845250509186019190860190610cd9565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c90821680610e2457607f821691505b602082108103610e5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610eaf576000816000526020600020601f850160051c81016020861015610e8c5750805b601f850160051c820191505b81811015610eab57828155600101610e98565b5050505b505050565b815167ffffffffffffffff811115610ece57610ece610b89565b610ee281610edc8454610e10565b84610e63565b602080601f831160018114610f355760008415610eff5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610eab565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610f8257888601518255948401946001909101908401610f63565b5085821015610fbe57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122090d4936e163063dfe747da5bf04cc06002b17436a13e78a30b2797e6219ebb2264736f6c63430008190033", + "deployedBytecode": "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c80639d6c76b81161005b5780639d6c76b8146100d5578063de46a235146100e8578063f9b80da1146100fb578063ff1575e11461014757600080fd5b806322473d8c14610082578063514aab87146100975780635666a5ea146100c2575b600080fd5b610095610090366004610ab8565b61015a565b005b6100aa6100a5366004610ad1565b61038d565b6040516100b993929190610af3565b60405180910390f35b6100956100d0366004610c59565b610492565b6100956100e3366004610c59565b610689565b6100956100f6366004610ab8565b61087f565b6101227f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b9565b6100aa610155366004610ad1565b610aa8565b60006001828154811061016f5761016f610de1565b600091825260208220015491505b818110156103545760006001848154811061019a5761019a610de1565b9060005260206000200182815481106101b5576101b5610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161020290610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461022e90610e10565b801561027b5780601f106102505761010080835404028352916020019161027b565b820191906000526020600020905b81548152906001019060200180831161025e57829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f545f7a320000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363545f7a329361031693909291600401610af3565b600060405180830381600087803b15801561033057600080fd5b505af1158015610344573d6000803e3d6000fd5b505050505080600101905061017d565b506040518281527f1382323d6618527d8b03daa05db815f0490966e8b80679fe5ad3d868f84e1a71906020015b60405180910390a15050565b6000828154811061039d57600080fd5b9060005260206000200181815481106103b557600080fd5b60009182526020909120600390910201805460018201805473ffffffffffffffffffffffffffffffffffffffff90921694509192506103f390610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461041f90610e10565b801561046c5780601f106104415761010080835404028352916020019161046c565b820191906000526020600020905b81548152906001019060200180831161044f57829003601f168201915b5050506002909301549192505073ffffffffffffffffffffffffffffffffffffffff1683565b80516000036104cd576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805480820182556000918252905b825181101561065857600182815481106104f9576104f9610de1565b90600052602060002001604051806060016040528085848151811061052057610520610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061055957610559610de1565b602002602001015160200151815260200185848151811061057c5761057c610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906106019082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016104dd565b506040518181527f75922591bf2cec980645dc4a32bb7d5e8da9a15fda86dacf06f8402cecd1478f90602001610381565b80516000036106c4576040517f4494013c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008054600181018255818052905b825181101561084e57600082815481106106ef576106ef610de1565b90600052602060002001604051806060016040528085848151811061071657610716610de1565b60200260200101516000015173ffffffffffffffffffffffffffffffffffffffff16815260200185848151811061074f5761074f610de1565b602002602001015160200151815260200185848151811061077257610772610de1565b6020908102919091018101516040015173ffffffffffffffffffffffffffffffffffffffff908116909252835460018082018655600095865294829020845160039092020180547fffffffffffffffffffffffff0000000000000000000000000000000000000000169190931617825582015191929091908201906107f79082610eb4565b5060409190910151600290910180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9092169190911790556001016106d3565b506040518181527ff8ca6ea7cc31be8572501c37ef5e9e8298be717fb881e0b1ca785aecc4d25e9f90602001610381565b600080828154811061089357610893610de1565b600091825260208220015491505b81811015610a775760008084815481106108bd576108bd610de1565b9060005260206000200182815481106108d8576108d8610de1565b60009182526020918290206040805160608101909152600390920201805473ffffffffffffffffffffffffffffffffffffffff168252600181018054929391929184019161092590610e10565b80601f016020809104026020016040519081016040528092919081815260200182805461095190610e10565b801561099e5780601f106109735761010080835404028352916020019161099e565b820191906000526020600020905b81548152906001019060200180831161098157829003601f168201915b50505091835250506002919091015473ffffffffffffffffffffffffffffffffffffffff90811660209283015282519183015160408085015190517f584f6b600000000000000000000000000000000000000000000000000000000081529495507f00000000000000000000000000000000000000000000000000000000000000009092169363584f6b6093610a3993909291600401610af3565b600060405180830381600087803b158015610a5357600080fd5b505af1158015610a67573d6000803e3d6000fd5b50505050508060010190506108a1565b506040518281527f01a805f459381af632ecab72ec192c3f9a4c72d26be089026ffd6636d82de98890602001610381565b6001828154811061039d57600080fd5b600060208284031215610aca57600080fd5b5035919050565b60008060408385031215610ae457600080fd5b50508035926020909101359150565b600073ffffffffffffffffffffffffffffffffffffffff8086168352602060606020850152855180606086015260005b81811015610b3f57878101830151868201608001528201610b23565b5060006080828701015260807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011686010193505050808416604084015250949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516060810167ffffffffffffffff81118282101715610bdb57610bdb610b89565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715610c2857610c28610b89565b604052919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c5457600080fd5b919050565b60006020808385031215610c6c57600080fd5b823567ffffffffffffffff80821115610c8457600080fd5b818501915085601f830112610c9857600080fd5b813581811115610caa57610caa610b89565b8060051b610cb9858201610be1565b9182528381018501918581019089841115610cd357600080fd5b86860192505b83831015610dd457823585811115610cf057600080fd5b86017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe06060828d0382011215610d265760008081fd5b610d2e610bb8565b610d398a8401610c30565b815260408084013589811115610d4f5760008081fd5b8401603f81018f13610d615760008081fd5b8b8101358a811115610d7557610d75610b89565b610d858d86601f84011601610be1565b94508085528f83828401011115610d9c5760008081fd5b808383018e87013760008d82870101525050828b830152610dbf60608501610c30565b90820152845250509186019190860190610cd9565b9998505050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600181811c90821680610e2457607f821691505b602082108103610e5d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610eaf576000816000526020600020601f850160051c81016020861015610e8c5750805b601f850160051c820191505b81811015610eab57828155600101610e98565b5050505b505050565b815167ffffffffffffffff811115610ece57610ece610b89565b610ee281610edc8454610e10565b84610e63565b602080601f831160018114610f355760008415610eff5750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555610eab565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015610f8257888601518255948401946001909101908401610f63565b5085821015610fbe57878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b0190555056fea264697066735822122090d4936e163063dfe747da5bf04cc06002b17436a13e78a30b2797e6219ebb2264736f6c63430008190033", + "devdoc": { + "author": "Venus", + "kind": "dev", + "methods": {}, + "title": "ACMCommandsAggregator", + "version": 1 + }, + "userdoc": { + "errors": { + "ZeroAddressNotAllowed()": [ + { + "notice": "Thrown if the supplied address is a zero address where it is not allowed" + } + ] + }, + "kind": "user", + "methods": { + "ACM()": { + "notice": "Access control manager contract" + } + }, + "notice": "This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.", + "version": 1 + }, + "storageLayout": { + "storage": [ + { + "astId": 8955, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "grantPermissions", + "offset": 0, + "slot": "0", + "type": "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage" + }, + { + "astId": 8960, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "revokePermissions", + "offset": 0, + "slot": "1", + "type": "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage" + } + ], + "types": { + "t_address": { + "encoding": "inplace", + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_array(t_struct(Permission)8946_storage)dyn_storage)dyn_storage": { + "base": "t_array(t_struct(Permission)8946_storage)dyn_storage", + "encoding": "dynamic_array", + "label": "struct ACMCommandsAggregator.Permission[][]", + "numberOfBytes": "32" + }, + "t_array(t_struct(Permission)8946_storage)dyn_storage": { + "base": "t_struct(Permission)8946_storage", + "encoding": "dynamic_array", + "label": "struct ACMCommandsAggregator.Permission[]", + "numberOfBytes": "32" + }, + "t_string_storage": { + "encoding": "bytes", + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Permission)8946_storage": { + "encoding": "inplace", + "label": "struct ACMCommandsAggregator.Permission", + "members": [ + { + "astId": 8941, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "contractAddress", + "offset": 0, + "slot": "0", + "type": "t_address" + }, + { + "astId": 8943, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "functionSig", + "offset": 0, + "slot": "1", + "type": "t_string_storage" + }, + { + "astId": 8945, + "contract": "contracts/Utils/ACMCommandsAggregator.sol:ACMCommandsAggregator", + "label": "account", + "offset": 0, + "slot": "2", + "type": "t_address" + } + ], + "numberOfBytes": "96" + } + } + } +} diff --git a/deployments/sepolia/solcInputs/06fc2b6f9f7e0e63c70222b8e0b27702.json b/deployments/sepolia/solcInputs/06fc2b6f9f7e0e63c70222b8e0b27702.json new file mode 100644 index 00000000..4dcea97a --- /dev/null +++ b/deployments/sepolia/solcInputs/06fc2b6f9f7e0e63c70222b8e0b27702.json @@ -0,0 +1,40 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "contracts/Governance/ACMCommandsAggregator.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport {IAccessControlManagerV8} from \"../Governance/IAccessControlManagerV8.sol\";\n\ncontract ACMCommandsAggregator {\n /*\n * @notice Enum to differentiate between giving and revoking permissions\n */\n enum PermissionType {\n GIVE,\n REVOKE\n }\n\n /*\n * @notice Struct to store permission details\n */\n struct Permission {\n /*\n * @notice Type of permission\n */ \n PermissionType permissionType;\n\n /*\n * @notice Address of the contract\n */\n address contractAddress;\n\n /*\n * @notice Function signature\n */\n string functionSig;\n\n /*\n * @notice Address of the account\n */\n address account;\n }\n\n /**\n * @notice Access control manager contract\n */\n IAccessControlManagerV8 immutable public ACM;\n\n /*\n * @notice Array to store permissions\n */\n Permission[][] public permissions;\n\n /*\n * @notice Constructor to set the access control manager\n * @param _acm Address of the access control manager\n */\n constructor(IAccessControlManagerV8 _acm) {\n ACM = _acm;\n }\n\n /*\n * @notice Function to add permissions\n * @param _permissions Array of permissions\n */\n function addPermissions(Permission[] memory _permissions) external {\n uint256 index = _permissions.length;\n for (uint256 i = 0; i < _permissions.length; i++) {\n permissions[index].push(_permissions[i]);\n }\n }\n\n /*\n * @notice Function to execute permissions\n * @param index Index of the permissions array\n */\n function executePermissions(uint256 index) external {\n for (uint256 i = 0; i < permissions[index].length; i++) {\n if (permissions[index][i].permissionType == PermissionType.GIVE) {\n ACM.giveCallPermission(permissions[index][i].contractAddress, permissions[index][i].functionSig, permissions[index][i].account);\n } else {\n ACM.revokeCallPermission(permissions[index][i].contractAddress, permissions[index][i].functionSig, permissions[index][i].account);\n }\n }\n }\n}" + }, + "contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 10000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/sepolia/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json b/deployments/sepolia/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json new file mode 100644 index 00000000..12855c7e --- /dev/null +++ b/deployments/sepolia/solcInputs/8462bae4a0ff7e7203ecab090cdf091c.json @@ -0,0 +1,151 @@ +{ + "language": "Solidity", + "sources": { + "@layerzerolabs/solidity-examples/contracts/libraries/BytesLib.sol": { + "content": "// SPDX-License-Identifier: Unlicense\n/*\n * @title Solidity Bytes Arrays Utils\n * @author Gonçalo Sá \n *\n * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.\n * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.\n */\npragma solidity >=0.8.0 <0.9.0;\n\nlibrary BytesLib {\n function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {\n bytes memory tempBytes;\n\n assembly {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // Store the length of the first bytes array at the beginning of\n // the memory for tempBytes.\n let length := mload(_preBytes)\n mstore(tempBytes, length)\n\n // Maintain a memory counter for the current write location in the\n // temp bytes array by adding the 32 bytes for the array length to\n // the starting location.\n let mc := add(tempBytes, 0x20)\n // Stop copying when the memory counter reaches the length of the\n // first bytes array.\n let end := add(mc, length)\n\n for {\n // Initialize a copy counter to the start of the _preBytes data,\n // 32 bytes into its memory.\n let cc := add(_preBytes, 0x20)\n } lt(mc, end) {\n // Increase both counters by 32 bytes each iteration.\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // Write the _preBytes data into the tempBytes memory 32 bytes\n // at a time.\n mstore(mc, mload(cc))\n }\n\n // Add the length of _postBytes to the current length of tempBytes\n // and store it as the new length in the first 32 bytes of the\n // tempBytes memory.\n length := mload(_postBytes)\n mstore(tempBytes, add(length, mload(tempBytes)))\n\n // Move the memory counter back from a multiple of 0x20 to the\n // actual end of the _preBytes data.\n mc := end\n // Stop copying when the memory counter reaches the new combined\n // length of the arrays.\n end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n // Update the free-memory pointer by padding our last write location\n // to 32 bytes: add 31 bytes to the end of tempBytes to move to the\n // next 32 byte block, then round down to the nearest multiple of\n // 32. If the sum of the length of the two arrays is zero then add\n // one before rounding down to leave a blank 32 bytes (the length block with 0).\n mstore(\n 0x40,\n and(\n add(add(end, iszero(add(length, mload(_preBytes)))), 31),\n not(31) // Round down to the nearest 32 bytes.\n )\n )\n }\n\n return tempBytes;\n }\n\n function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {\n assembly {\n // Read the first 32 bytes of _preBytes storage, which is the length\n // of the array. (We don't need to use the offset into the slot\n // because arrays use the entire slot.)\n let fslot := sload(_preBytes.slot)\n // Arrays of 31 bytes or less have an even value in their slot,\n // while longer arrays have an odd value. The actual length is\n // the slot divided by two for odd values, and the lowest order\n // byte divided by two for even values.\n // If the slot is even, bitwise and the slot with 255 and divide by\n // two to get the length. If the slot is odd, bitwise and the slot\n // with -1 and divide by two.\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n let newlength := add(slength, mlength)\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n switch add(lt(slength, 32), lt(newlength, 32))\n case 2 {\n // Since the new array still fits in the slot, we just need to\n // update the contents of the slot.\n // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length\n sstore(\n _preBytes.slot,\n // all the modifications to the slot are inside this\n // next block\n add(\n // we can just add to the slot contents because the\n // bytes we want to change are the LSBs\n fslot,\n add(\n mul(\n div(\n // load the bytes from memory\n mload(add(_postBytes, 0x20)),\n // zero all bytes to the right\n exp(0x100, sub(32, mlength))\n ),\n // and now shift left the number of bytes to\n // leave space for the length in the slot\n exp(0x100, sub(32, newlength))\n ),\n // increase length by the double of the memory\n // bytes length\n mul(mlength, 2)\n )\n )\n )\n }\n case 1 {\n // The stored value fits in the slot, but the combined value\n // will exceed it.\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // The contents of the _postBytes array start 32 bytes into\n // the structure. Our first read should obtain the `submod`\n // bytes that can fit into the unused space in the last word\n // of the stored array. To get this, we read 32 bytes starting\n // from `submod`, so the data we read overlaps with the array\n // contents by `submod` bytes. Masking the lowest-order\n // `submod` bytes allows us to add that value directly to the\n // stored value.\n\n let submod := sub(32, slength)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00), and(mload(mc), mask)))\n\n for {\n mc := add(mc, 0x20)\n sc := add(sc, 1)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n default {\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n // Start copying to the last used word of the stored array.\n let sc := add(keccak256(0x0, 0x20), div(slength, 32))\n\n // save new length\n sstore(_preBytes.slot, add(mul(newlength, 2), 1))\n\n // Copy over the first `submod` bytes of the new data as in\n // case 1 above.\n let slengthmod := mod(slength, 32)\n let mlengthmod := mod(mlength, 32)\n let submod := sub(32, slengthmod)\n let mc := add(_postBytes, submod)\n let end := add(_postBytes, mlength)\n let mask := sub(exp(0x100, submod), 1)\n\n sstore(sc, add(sload(sc), and(mload(mc), mask)))\n\n for {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } lt(mc, end) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n sstore(sc, mload(mc))\n }\n\n mask := exp(0x100, sub(mc, end))\n\n sstore(sc, mul(div(mload(mc), mask), mask))\n }\n }\n }\n\n function slice(\n bytes memory _bytes,\n uint _start,\n uint _length\n ) internal pure returns (bytes memory) {\n require(_length + 31 >= _length, \"slice_overflow\");\n require(_bytes.length >= _start + _length, \"slice_outOfBounds\");\n\n bytes memory tempBytes;\n\n assembly {\n switch iszero(_length)\n case 0 {\n // Get a location of some free memory and store it in tempBytes as\n // Solidity does for memory variables.\n tempBytes := mload(0x40)\n\n // The first word of the slice result is potentially a partial\n // word read from the original array. To read it, we calculate\n // the length of that partial word and start copying that many\n // bytes into the array. The first word we copy will start with\n // data we don't care about, but the last `lengthmod` bytes will\n // land at the beginning of the contents of the new array. When\n // we're done copying, we overwrite the full first word with\n // the actual length of the slice.\n let lengthmod := and(_length, 31)\n\n // The multiplication in the next line is necessary\n // because when slicing multiples of 32 bytes (lengthmod == 0)\n // the following copy loop was copying the origin's length\n // and then ending prematurely not copying everything it should.\n let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))\n let end := add(mc, _length)\n\n for {\n // The multiplication in the next line has the same exact purpose\n // as the one above.\n let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)\n } lt(mc, end) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n mstore(mc, mload(cc))\n }\n\n mstore(tempBytes, _length)\n\n //update free-memory pointer\n //allocating the array padded to 32 bytes like the compiler does now\n mstore(0x40, and(add(mc, 31), not(31)))\n }\n //if we want a zero-length slice let's just return a zero-length array\n default {\n tempBytes := mload(0x40)\n //zero out the 32 bytes slice we are about to return\n //we need to do it because Solidity does not garbage collect\n mstore(tempBytes, 0)\n\n mstore(0x40, add(tempBytes, 0x20))\n }\n }\n\n return tempBytes;\n }\n\n function toAddress(bytes memory _bytes, uint _start) internal pure returns (address) {\n require(_bytes.length >= _start + 20, \"toAddress_outOfBounds\");\n address tempAddress;\n\n assembly {\n tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)\n }\n\n return tempAddress;\n }\n\n function toUint8(bytes memory _bytes, uint _start) internal pure returns (uint8) {\n require(_bytes.length >= _start + 1, \"toUint8_outOfBounds\");\n uint8 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x1), _start))\n }\n\n return tempUint;\n }\n\n function toUint16(bytes memory _bytes, uint _start) internal pure returns (uint16) {\n require(_bytes.length >= _start + 2, \"toUint16_outOfBounds\");\n uint16 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x2), _start))\n }\n\n return tempUint;\n }\n\n function toUint32(bytes memory _bytes, uint _start) internal pure returns (uint32) {\n require(_bytes.length >= _start + 4, \"toUint32_outOfBounds\");\n uint32 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x4), _start))\n }\n\n return tempUint;\n }\n\n function toUint64(bytes memory _bytes, uint _start) internal pure returns (uint64) {\n require(_bytes.length >= _start + 8, \"toUint64_outOfBounds\");\n uint64 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x8), _start))\n }\n\n return tempUint;\n }\n\n function toUint96(bytes memory _bytes, uint _start) internal pure returns (uint96) {\n require(_bytes.length >= _start + 12, \"toUint96_outOfBounds\");\n uint96 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0xc), _start))\n }\n\n return tempUint;\n }\n\n function toUint128(bytes memory _bytes, uint _start) internal pure returns (uint128) {\n require(_bytes.length >= _start + 16, \"toUint128_outOfBounds\");\n uint128 tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x10), _start))\n }\n\n return tempUint;\n }\n\n function toUint256(bytes memory _bytes, uint _start) internal pure returns (uint) {\n require(_bytes.length >= _start + 32, \"toUint256_outOfBounds\");\n uint tempUint;\n\n assembly {\n tempUint := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempUint;\n }\n\n function toBytes32(bytes memory _bytes, uint _start) internal pure returns (bytes32) {\n require(_bytes.length >= _start + 32, \"toBytes32_outOfBounds\");\n bytes32 tempBytes32;\n\n assembly {\n tempBytes32 := mload(add(add(_bytes, 0x20), _start))\n }\n\n return tempBytes32;\n }\n\n function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {\n bool success = true;\n\n assembly {\n let length := mload(_preBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(length, mload(_postBytes))\n case 1 {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n let mc := add(_preBytes, 0x20)\n let end := add(mc, length)\n\n for {\n let cc := add(_postBytes, 0x20)\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n } eq(add(lt(mc, end), cb), 2) {\n mc := add(mc, 0x20)\n cc := add(cc, 0x20)\n } {\n // if any of these checks fails then arrays are not equal\n if iszero(eq(mload(mc), mload(cc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n\n function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {\n bool success = true;\n\n assembly {\n // we know _preBytes_offset is 0\n let fslot := sload(_preBytes.slot)\n // Decode the length of the stored array like in concatStorage().\n let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)\n let mlength := mload(_postBytes)\n\n // if lengths don't match the arrays are not equal\n switch eq(slength, mlength)\n case 1 {\n // slength can contain both the length and contents of the array\n // if length < 32 bytes so let's prepare for that\n // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage\n if iszero(iszero(slength)) {\n switch lt(slength, 32)\n case 1 {\n // blank the last byte which is the length\n fslot := mul(div(fslot, 0x100), 0x100)\n\n if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {\n // unsuccess:\n success := 0\n }\n }\n default {\n // cb is a circuit breaker in the for loop since there's\n // no said feature for inline assembly loops\n // cb = 1 - don't breaker\n // cb = 0 - break\n let cb := 1\n\n // get the keccak hash to get the contents of the array\n mstore(0x0, _preBytes.slot)\n let sc := keccak256(0x0, 0x20)\n\n let mc := add(_postBytes, 0x20)\n let end := add(mc, mlength)\n\n // the next line is the loop condition:\n // while(uint256(mc < end) + cb == 2)\n for {\n\n } eq(add(lt(mc, end), cb), 2) {\n sc := add(sc, 1)\n mc := add(mc, 0x20)\n } {\n if iszero(eq(sload(sc), mload(mc))) {\n // unsuccess:\n success := 0\n cb := 0\n }\n }\n }\n }\n }\n default {\n // unsuccess:\n success := 0\n }\n }\n\n return success;\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/libraries/ExcessivelySafeCall.sol": { + "content": "// SPDX-License-Identifier: MIT OR Apache-2.0\npragma solidity >=0.7.6;\n\nlibrary ExcessivelySafeCall {\n uint constant LOW_28_MASK = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeCall(\n address _target,\n uint _gas,\n uint16 _maxCopy,\n bytes memory _calldata\n ) internal returns (bool, bytes memory) {\n // set up for assembly call\n uint _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly {\n _success := call(\n _gas, // gas\n _target, // recipient\n 0, // ether value\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) {\n _toCopy := _maxCopy\n }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /// @notice Use when you _really_ really _really_ don't trust the called\n /// contract. This prevents the called contract from causing reversion of\n /// the caller in as many ways as we can.\n /// @dev The main difference between this and a solidity low-level call is\n /// that we limit the number of bytes that the callee can cause to be\n /// copied to caller memory. This prevents stupid things like malicious\n /// contracts returning 10,000,000 bytes causing a local OOG when copying\n /// to memory.\n /// @param _target The address to call\n /// @param _gas The amount of gas to forward to the remote contract\n /// @param _maxCopy The maximum number of bytes of returndata to copy\n /// to memory.\n /// @param _calldata The data to send to the remote contract\n /// @return success and returndata, as `.call()`. Returndata is capped to\n /// `_maxCopy` bytes.\n function excessivelySafeStaticCall(\n address _target,\n uint _gas,\n uint16 _maxCopy,\n bytes memory _calldata\n ) internal view returns (bool, bytes memory) {\n // set up for assembly call\n uint _toCopy;\n bool _success;\n bytes memory _returnData = new bytes(_maxCopy);\n // dispatch message to recipient\n // by assembly calling \"handle\" function\n // we call via assembly to avoid memcopying a very large returndata\n // returned by a malicious contract\n assembly {\n _success := staticcall(\n _gas, // gas\n _target, // recipient\n add(_calldata, 0x20), // inloc\n mload(_calldata), // inlen\n 0, // outloc\n 0 // outlen\n )\n // limit our copy to 256 bytes\n _toCopy := returndatasize()\n if gt(_toCopy, _maxCopy) {\n _toCopy := _maxCopy\n }\n // Store the length of the copied bytes\n mstore(_returnData, _toCopy)\n // copy the bytes from returndata[0:_toCopy]\n returndatacopy(add(_returnData, 0x20), 0, _toCopy)\n }\n return (_success, _returnData);\n }\n\n /**\n * @notice Swaps function selectors in encoded contract calls\n * @dev Allows reuse of encoded calldata for functions with identical\n * argument types but different names. It simply swaps out the first 4 bytes\n * for the new selector. This function modifies memory in place, and should\n * only be used with caution.\n * @param _newSelector The new 4-byte selector\n * @param _buf The encoded contract args\n */\n function swapSelector(bytes4 _newSelector, bytes memory _buf) internal pure {\n require(_buf.length >= 4);\n uint _mask = LOW_28_MASK;\n assembly {\n // load the first word of\n let _word := mload(add(_buf, 0x20))\n // mask out the top 4 bytes\n // /x\n _word := and(_word, _mask)\n _word := or(_newSelector, _word)\n mstore(add(_buf, 0x20), _word)\n }\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\nimport \"./ILayerZeroUserApplicationConfig.sol\";\n\ninterface ILayerZeroEndpoint is ILayerZeroUserApplicationConfig {\n // @notice send a LayerZero message to the specified address at a LayerZero endpoint.\n // @param _dstChainId - the destination chain identifier\n // @param _destination - the address on destination chain (in bytes). address length/format may vary by chains\n // @param _payload - a custom bytes payload to send to the destination contract\n // @param _refundAddress - if the source transaction is cheaper than the amount of value passed, refund the additional amount to this address\n // @param _zroPaymentAddress - the address of the ZRO token holder who would pay for the transaction\n // @param _adapterParams - parameters for custom functionality. e.g. receive airdropped native gas from the relayer on destination\n function send(\n uint16 _dstChainId,\n bytes calldata _destination,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes calldata _adapterParams\n ) external payable;\n\n // @notice used by the messaging library to publish verified payload\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source contract (as bytes) at the source chain\n // @param _dstAddress - the address on destination chain\n // @param _nonce - the unbound message ordering nonce\n // @param _gasLimit - the gas limit for external contract execution\n // @param _payload - verified payload to send to the destination contract\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n address _dstAddress,\n uint64 _nonce,\n uint _gasLimit,\n bytes calldata _payload\n ) external;\n\n // @notice get the inboundNonce of a lzApp from a source chain which could be EVM or non-EVM chain\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function getInboundNonce(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint64);\n\n // @notice get the outboundNonce from this source chain which, consequently, is always an EVM\n // @param _srcAddress - the source chain contract address\n function getOutboundNonce(uint16 _dstChainId, address _srcAddress) external view returns (uint64);\n\n // @notice gets a quote in source native gas, for the amount that send() requires to pay for message delivery\n // @param _dstChainId - the destination chain identifier\n // @param _userApplication - the user app address on this EVM chain\n // @param _payload - the custom message to send over LayerZero\n // @param _payInZRO - if false, user app pays the protocol fee in native token\n // @param _adapterParam - parameters for the adapter service, e.g. send some dust native token to dstChain\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes calldata _payload,\n bool _payInZRO,\n bytes calldata _adapterParam\n ) external view returns (uint nativeFee, uint zroFee);\n\n // @notice get this Endpoint's immutable source identifier\n function getChainId() external view returns (uint16);\n\n // @notice the interface to retry failed message on this Endpoint destination\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n // @param _payload - the payload to be retried\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n bytes calldata _payload\n ) external;\n\n // @notice query if any STORED payload (message blocking) at the endpoint.\n // @param _srcChainId - the source chain identifier\n // @param _srcAddress - the source chain contract address\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool);\n\n // @notice query if the _libraryAddress is valid for sending msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getSendLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the _libraryAddress is valid for receiving msgs.\n // @param _userApplication - the user app address on this EVM chain\n function getReceiveLibraryAddress(address _userApplication) external view returns (address);\n\n // @notice query if the non-reentrancy guard for send() is on\n // @return true if the guard is on. false otherwise\n function isSendingPayload() external view returns (bool);\n\n // @notice query if the non-reentrancy guard for receive() is on\n // @return true if the guard is on. false otherwise\n function isReceivingPayload() external view returns (bool);\n\n // @notice get the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _userApplication - the contract address of the user application\n // @param _configType - type of configuration. every messaging library has its own convention.\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address _userApplication,\n uint _configType\n ) external view returns (bytes memory);\n\n // @notice get the send() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getSendVersion(address _userApplication) external view returns (uint16);\n\n // @notice get the lzReceive() LayerZero messaging library version\n // @param _userApplication - the contract address of the user application\n function getReceiveVersion(address _userApplication) external view returns (uint16);\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroReceiver.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroReceiver {\n // @notice LayerZero endpoint will invoke this function to deliver the message on the destination\n // @param _srcChainId - the source endpoint identifier\n // @param _srcAddress - the source sending contract address from the source chain\n // @param _nonce - the ordered message nonce\n // @param _payload - the signed payload is the UA bytes has encoded to be sent\n function lzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) external;\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroUserApplicationConfig.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity >=0.5.0;\n\ninterface ILayerZeroUserApplicationConfig {\n // @notice set the configuration of the LayerZero messaging library of the specified version\n // @param _version - messaging library version\n // @param _chainId - the chainId for the pending config change\n // @param _configType - type of configuration. every messaging library has its own convention.\n // @param _config - configuration in the bytes. can encode arbitrary content.\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint _configType,\n bytes calldata _config\n ) external;\n\n // @notice set the send() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setSendVersion(uint16 _version) external;\n\n // @notice set the lzReceive() LayerZero messaging library version to _version\n // @param _version - new messaging library version\n function setReceiveVersion(uint16 _version) external;\n\n // @notice Only when the UA needs to resume the message flow in blocking mode and clear the stored payload\n // @param _srcChainId - the chainId of the source chain\n // @param _srcAddress - the contract address of the source contract at the source chain\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external;\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/libs/LzLib.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity >=0.6.0;\npragma experimental ABIEncoderV2;\n\nlibrary LzLib {\n // LayerZero communication\n struct CallParams {\n address payable refundAddress;\n address zroPaymentAddress;\n }\n\n //---------------------------------------------------------------------------\n // Address type handling\n\n struct AirdropParams {\n uint airdropAmount;\n bytes32 airdropAddress;\n }\n\n function buildAdapterParams(LzLib.AirdropParams memory _airdropParams, uint _uaGasLimit) internal pure returns (bytes memory adapterParams) {\n if (_airdropParams.airdropAmount == 0 && _airdropParams.airdropAddress == bytes32(0x0)) {\n adapterParams = buildDefaultAdapterParams(_uaGasLimit);\n } else {\n adapterParams = buildAirdropAdapterParams(_uaGasLimit, _airdropParams);\n }\n }\n\n // Build Adapter Params\n function buildDefaultAdapterParams(uint _uaGas) internal pure returns (bytes memory) {\n // txType 1\n // bytes [2 32 ]\n // fields [txType extraGas]\n return abi.encodePacked(uint16(1), _uaGas);\n }\n\n function buildAirdropAdapterParams(uint _uaGas, AirdropParams memory _params) internal pure returns (bytes memory) {\n require(_params.airdropAmount > 0, \"Airdrop amount must be greater than 0\");\n require(_params.airdropAddress != bytes32(0x0), \"Airdrop address must be set\");\n\n // txType 2\n // bytes [2 32 32 bytes[] ]\n // fields [txType extraGas dstNativeAmt dstNativeAddress]\n return abi.encodePacked(uint16(2), _uaGas, _params.airdropAmount, _params.airdropAddress);\n }\n\n function getGasLimit(bytes memory _adapterParams) internal pure returns (uint gasLimit) {\n require(_adapterParams.length == 34 || _adapterParams.length > 66, \"Invalid adapterParams\");\n assembly {\n gasLimit := mload(add(_adapterParams, 34))\n }\n }\n\n // Decode Adapter Params\n function decodeAdapterParams(bytes memory _adapterParams)\n internal\n pure\n returns (\n uint16 txType,\n uint uaGas,\n uint airdropAmount,\n address payable airdropAddress\n )\n {\n require(_adapterParams.length == 34 || _adapterParams.length > 66, \"Invalid adapterParams\");\n assembly {\n txType := mload(add(_adapterParams, 2))\n uaGas := mload(add(_adapterParams, 34))\n }\n require(txType == 1 || txType == 2, \"Unsupported txType\");\n require(uaGas > 0, \"Gas too low\");\n\n if (txType == 2) {\n assembly {\n airdropAmount := mload(add(_adapterParams, 66))\n airdropAddress := mload(add(_adapterParams, 86))\n }\n }\n }\n\n //---------------------------------------------------------------------------\n // Address type handling\n function bytes32ToAddress(bytes32 _bytes32Address) internal pure returns (address _address) {\n return address(uint160(uint(_bytes32Address)));\n }\n\n function addressToBytes32(address _address) internal pure returns (bytes32 _bytes32Address) {\n return bytes32(uint(uint160(_address)));\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/LzApp.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"./interfaces/ILayerZeroReceiver.sol\";\nimport \"./interfaces/ILayerZeroUserApplicationConfig.sol\";\nimport \"./interfaces/ILayerZeroEndpoint.sol\";\nimport \"../libraries/BytesLib.sol\";\n\n/*\n * a generic LzReceiver implementation\n */\nabstract contract LzApp is Ownable, ILayerZeroReceiver, ILayerZeroUserApplicationConfig {\n using BytesLib for bytes;\n\n // ua can not send payload larger than this by default, but it can be changed by the ua owner\n uint public constant DEFAULT_PAYLOAD_SIZE_LIMIT = 10000;\n\n ILayerZeroEndpoint public immutable lzEndpoint;\n mapping(uint16 => bytes) public trustedRemoteLookup;\n mapping(uint16 => mapping(uint16 => uint)) public minDstGasLookup;\n mapping(uint16 => uint) public payloadSizeLimitLookup;\n address public precrime;\n\n event SetPrecrime(address precrime);\n event SetTrustedRemote(uint16 _remoteChainId, bytes _path);\n event SetTrustedRemoteAddress(uint16 _remoteChainId, bytes _remoteAddress);\n event SetMinDstGas(uint16 _dstChainId, uint16 _type, uint _minDstGas);\n\n constructor(address _endpoint) {\n lzEndpoint = ILayerZeroEndpoint(_endpoint);\n }\n\n function lzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public virtual override {\n // lzReceive must be called by the endpoint for security\n require(_msgSender() == address(lzEndpoint), \"LzApp: invalid endpoint caller\");\n\n bytes memory trustedRemote = trustedRemoteLookup[_srcChainId];\n // if will still block the message pathway from (srcChainId, srcAddress). should not receive message from untrusted remote.\n require(\n _srcAddress.length == trustedRemote.length && trustedRemote.length > 0 && keccak256(_srcAddress) == keccak256(trustedRemote),\n \"LzApp: invalid source sending contract\"\n );\n\n _blockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n // abstract function - the default behaviour of LayerZero is blocking. See: NonblockingLzApp if you dont need to enforce ordered messaging\n function _blockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual;\n\n function _lzSend(\n uint16 _dstChainId,\n bytes memory _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams,\n uint _nativeFee\n ) internal virtual {\n bytes memory trustedRemote = trustedRemoteLookup[_dstChainId];\n require(trustedRemote.length != 0, \"LzApp: destination chain is not a trusted source\");\n _checkPayloadSize(_dstChainId, _payload.length);\n lzEndpoint.send{value: _nativeFee}(_dstChainId, trustedRemote, _payload, _refundAddress, _zroPaymentAddress, _adapterParams);\n }\n\n function _checkGasLimit(\n uint16 _dstChainId,\n uint16 _type,\n bytes memory _adapterParams,\n uint _extraGas\n ) internal view virtual {\n uint providedGasLimit = _getGasLimit(_adapterParams);\n uint minGasLimit = minDstGasLookup[_dstChainId][_type];\n require(minGasLimit > 0, \"LzApp: minGasLimit not set\");\n require(providedGasLimit >= minGasLimit + _extraGas, \"LzApp: gas limit is too low\");\n }\n\n function _getGasLimit(bytes memory _adapterParams) internal pure virtual returns (uint gasLimit) {\n require(_adapterParams.length >= 34, \"LzApp: invalid adapterParams\");\n assembly {\n gasLimit := mload(add(_adapterParams, 34))\n }\n }\n\n function _checkPayloadSize(uint16 _dstChainId, uint _payloadSize) internal view virtual {\n uint payloadSizeLimit = payloadSizeLimitLookup[_dstChainId];\n if (payloadSizeLimit == 0) {\n // use default if not set\n payloadSizeLimit = DEFAULT_PAYLOAD_SIZE_LIMIT;\n }\n require(_payloadSize <= payloadSizeLimit, \"LzApp: payload size is too large\");\n }\n\n //---------------------------UserApplication config----------------------------------------\n function getConfig(\n uint16 _version,\n uint16 _chainId,\n address,\n uint _configType\n ) external view returns (bytes memory) {\n return lzEndpoint.getConfig(_version, _chainId, address(this), _configType);\n }\n\n // generic config for LayerZero user Application\n function setConfig(\n uint16 _version,\n uint16 _chainId,\n uint _configType,\n bytes calldata _config\n ) external override onlyOwner {\n lzEndpoint.setConfig(_version, _chainId, _configType, _config);\n }\n\n function setSendVersion(uint16 _version) external override onlyOwner {\n lzEndpoint.setSendVersion(_version);\n }\n\n function setReceiveVersion(uint16 _version) external override onlyOwner {\n lzEndpoint.setReceiveVersion(_version);\n }\n\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _srcAddress) external override onlyOwner {\n lzEndpoint.forceResumeReceive(_srcChainId, _srcAddress);\n }\n\n // _path = abi.encodePacked(remoteAddress, localAddress)\n // this function set the trusted path for the cross-chain communication\n function setTrustedRemote(uint16 _remoteChainId, bytes calldata _path) external onlyOwner {\n trustedRemoteLookup[_remoteChainId] = _path;\n emit SetTrustedRemote(_remoteChainId, _path);\n }\n\n function setTrustedRemoteAddress(uint16 _remoteChainId, bytes calldata _remoteAddress) external onlyOwner {\n trustedRemoteLookup[_remoteChainId] = abi.encodePacked(_remoteAddress, address(this));\n emit SetTrustedRemoteAddress(_remoteChainId, _remoteAddress);\n }\n\n function getTrustedRemoteAddress(uint16 _remoteChainId) external view returns (bytes memory) {\n bytes memory path = trustedRemoteLookup[_remoteChainId];\n require(path.length != 0, \"LzApp: no trusted path record\");\n return path.slice(0, path.length - 20); // the last 20 bytes should be address(this)\n }\n\n function setPrecrime(address _precrime) external onlyOwner {\n precrime = _precrime;\n emit SetPrecrime(_precrime);\n }\n\n function setMinDstGas(\n uint16 _dstChainId,\n uint16 _packetType,\n uint _minGas\n ) external onlyOwner {\n minDstGasLookup[_dstChainId][_packetType] = _minGas;\n emit SetMinDstGas(_dstChainId, _packetType, _minGas);\n }\n\n // if the size is 0, it means default size limit\n function setPayloadSizeLimit(uint16 _dstChainId, uint _size) external onlyOwner {\n payloadSizeLimitLookup[_dstChainId] = _size;\n }\n\n //--------------------------- VIEW FUNCTION ----------------------------------------\n function isTrustedRemote(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (bool) {\n bytes memory trustedSource = trustedRemoteLookup[_srcChainId];\n return keccak256(trustedSource) == keccak256(_srcAddress);\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/mocks/LZEndpointMock.sol": { + "content": "// SPDX-License-Identifier: BUSL-1.1\n\npragma solidity ^0.8.0;\npragma abicoder v2;\n\nimport \"../interfaces/ILayerZeroReceiver.sol\";\nimport \"../interfaces/ILayerZeroEndpoint.sol\";\nimport \"../libs/LzLib.sol\";\n\n/*\nlike a real LayerZero endpoint but can be mocked, which handle message transmission, verification, and receipt.\n- blocking: LayerZero provides ordered delivery of messages from a given sender to a destination chain.\n- non-reentrancy: endpoint has a non-reentrancy guard for both the send() and receive(), respectively.\n- adapter parameters: allows UAs to add arbitrary transaction params in the send() function, like airdrop on destination chain.\nunlike a real LayerZero endpoint, it is\n- no messaging library versioning\n- send() will short circuit to lzReceive()\n- no user application configuration\n*/\ncontract LZEndpointMock is ILayerZeroEndpoint {\n uint8 internal constant _NOT_ENTERED = 1;\n uint8 internal constant _ENTERED = 2;\n\n mapping(address => address) public lzEndpointLookup;\n\n uint16 public mockChainId;\n bool public nextMsgBlocked;\n\n // fee config\n RelayerFeeConfig public relayerFeeConfig;\n ProtocolFeeConfig public protocolFeeConfig;\n uint public oracleFee;\n bytes public defaultAdapterParams;\n\n // path = remote addrss + local address\n // inboundNonce = [srcChainId][path].\n mapping(uint16 => mapping(bytes => uint64)) public inboundNonce;\n //todo: this is a hack\n // outboundNonce = [dstChainId][srcAddress]\n mapping(uint16 => mapping(address => uint64)) public outboundNonce;\n // // outboundNonce = [dstChainId][path].\n // mapping(uint16 => mapping(bytes => uint64)) public outboundNonce;\n // storedPayload = [srcChainId][path]\n mapping(uint16 => mapping(bytes => StoredPayload)) public storedPayload;\n // msgToDeliver = [srcChainId][path]\n mapping(uint16 => mapping(bytes => QueuedPayload[])) public msgsToDeliver;\n\n // reentrancy guard\n uint8 internal _send_entered_state = 1;\n uint8 internal _receive_entered_state = 1;\n\n struct ProtocolFeeConfig {\n uint zroFee;\n uint nativeBP;\n }\n\n struct RelayerFeeConfig {\n uint128 dstPriceRatio; // 10^10\n uint128 dstGasPriceInWei;\n uint128 dstNativeAmtCap;\n uint64 baseGas;\n uint64 gasPerByte;\n }\n\n struct StoredPayload {\n uint64 payloadLength;\n address dstAddress;\n bytes32 payloadHash;\n }\n\n struct QueuedPayload {\n address dstAddress;\n uint64 nonce;\n bytes payload;\n }\n\n modifier sendNonReentrant() {\n require(_send_entered_state == _NOT_ENTERED, \"LayerZeroMock: no send reentrancy\");\n _send_entered_state = _ENTERED;\n _;\n _send_entered_state = _NOT_ENTERED;\n }\n\n modifier receiveNonReentrant() {\n require(_receive_entered_state == _NOT_ENTERED, \"LayerZeroMock: no receive reentrancy\");\n _receive_entered_state = _ENTERED;\n _;\n _receive_entered_state = _NOT_ENTERED;\n }\n\n event UaForceResumeReceive(uint16 chainId, bytes srcAddress);\n event PayloadCleared(uint16 srcChainId, bytes srcAddress, uint64 nonce, address dstAddress);\n event PayloadStored(uint16 srcChainId, bytes srcAddress, address dstAddress, uint64 nonce, bytes payload, bytes reason);\n event ValueTransferFailed(address indexed to, uint indexed quantity);\n\n constructor(uint16 _chainId) {\n mockChainId = _chainId;\n\n // init config\n relayerFeeConfig = RelayerFeeConfig({\n dstPriceRatio: 1e10, // 1:1, same chain, same native coin\n dstGasPriceInWei: 1e10,\n dstNativeAmtCap: 1e19,\n baseGas: 100,\n gasPerByte: 1\n });\n protocolFeeConfig = ProtocolFeeConfig({zroFee: 1e18, nativeBP: 1000}); // BP 0.1\n oracleFee = 1e16;\n defaultAdapterParams = LzLib.buildDefaultAdapterParams(200000);\n }\n\n // ------------------------------ ILayerZeroEndpoint Functions ------------------------------\n function send(\n uint16 _chainId,\n bytes memory _path,\n bytes calldata _payload,\n address payable _refundAddress,\n address _zroPaymentAddress,\n bytes memory _adapterParams\n ) external payable override sendNonReentrant {\n require(_path.length == 40, \"LayerZeroMock: incorrect remote address size\"); // only support evm chains\n\n address dstAddr;\n assembly {\n dstAddr := mload(add(_path, 20))\n }\n\n address lzEndpoint = lzEndpointLookup[dstAddr];\n require(lzEndpoint != address(0), \"LayerZeroMock: destination LayerZero Endpoint not found\");\n\n // not handle zro token\n bytes memory adapterParams = _adapterParams.length > 0 ? _adapterParams : defaultAdapterParams;\n (uint nativeFee, ) = estimateFees(_chainId, msg.sender, _payload, _zroPaymentAddress != address(0x0), adapterParams);\n require(msg.value >= nativeFee, \"LayerZeroMock: not enough native for fees\");\n\n uint64 nonce = ++outboundNonce[_chainId][msg.sender];\n\n // refund if they send too much\n uint amount = msg.value - nativeFee;\n if (amount > 0) {\n (bool success, ) = _refundAddress.call{value: amount}(\"\");\n require(success, \"LayerZeroMock: failed to refund\");\n }\n\n // Mock the process of receiving msg on dst chain\n // Mock the relayer paying the dstNativeAddr the amount of extra native token\n (, uint extraGas, uint dstNativeAmt, address payable dstNativeAddr) = LzLib.decodeAdapterParams(adapterParams);\n if (dstNativeAmt > 0) {\n (bool success, ) = dstNativeAddr.call{value: dstNativeAmt}(\"\");\n if (!success) {\n emit ValueTransferFailed(dstNativeAddr, dstNativeAmt);\n }\n }\n\n bytes memory srcUaAddress = abi.encodePacked(msg.sender, dstAddr); // cast this address to bytes\n bytes memory payload = _payload;\n LZEndpointMock(lzEndpoint).receivePayload(mockChainId, srcUaAddress, dstAddr, nonce, extraGas, payload);\n }\n\n function receivePayload(\n uint16 _srcChainId,\n bytes calldata _path,\n address _dstAddress,\n uint64 _nonce,\n uint _gasLimit,\n bytes calldata _payload\n ) external override receiveNonReentrant {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n\n // assert and increment the nonce. no message shuffling\n require(_nonce == ++inboundNonce[_srcChainId][_path], \"LayerZeroMock: wrong nonce\");\n\n // queue the following msgs inside of a stack to simulate a successful send on src, but not fully delivered on dst\n if (sp.payloadHash != bytes32(0)) {\n QueuedPayload[] storage msgs = msgsToDeliver[_srcChainId][_path];\n QueuedPayload memory newMsg = QueuedPayload(_dstAddress, _nonce, _payload);\n\n // warning, might run into gas issues trying to forward through a bunch of queued msgs\n // shift all the msgs over so we can treat this like a fifo via array.pop()\n if (msgs.length > 0) {\n // extend the array\n msgs.push(newMsg);\n\n // shift all the indexes up for pop()\n for (uint i = 0; i < msgs.length - 1; i++) {\n msgs[i + 1] = msgs[i];\n }\n\n // put the newMsg at the bottom of the stack\n msgs[0] = newMsg;\n } else {\n msgs.push(newMsg);\n }\n } else if (nextMsgBlocked) {\n storedPayload[_srcChainId][_path] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));\n emit PayloadStored(_srcChainId, _path, _dstAddress, _nonce, _payload, bytes(\"\"));\n // ensure the next msgs that go through are no longer blocked\n nextMsgBlocked = false;\n } else {\n try ILayerZeroReceiver(_dstAddress).lzReceive{gas: _gasLimit}(_srcChainId, _path, _nonce, _payload) {} catch (bytes memory reason) {\n storedPayload[_srcChainId][_path] = StoredPayload(uint64(_payload.length), _dstAddress, keccak256(_payload));\n emit PayloadStored(_srcChainId, _path, _dstAddress, _nonce, _payload, reason);\n // ensure the next msgs that go through are no longer blocked\n nextMsgBlocked = false;\n }\n }\n }\n\n function getInboundNonce(uint16 _chainID, bytes calldata _path) external view override returns (uint64) {\n return inboundNonce[_chainID][_path];\n }\n\n function getOutboundNonce(uint16 _chainID, address _srcAddress) external view override returns (uint64) {\n return outboundNonce[_chainID][_srcAddress];\n }\n\n function estimateFees(\n uint16 _dstChainId,\n address _userApplication,\n bytes memory _payload,\n bool _payInZRO,\n bytes memory _adapterParams\n ) public view override returns (uint nativeFee, uint zroFee) {\n bytes memory adapterParams = _adapterParams.length > 0 ? _adapterParams : defaultAdapterParams;\n\n // Relayer Fee\n uint relayerFee = _getRelayerFee(_dstChainId, 1, _userApplication, _payload.length, adapterParams);\n\n // LayerZero Fee\n uint protocolFee = _getProtocolFees(_payInZRO, relayerFee, oracleFee);\n _payInZRO ? zroFee = protocolFee : nativeFee = protocolFee;\n\n // return the sum of fees\n nativeFee = nativeFee + relayerFee + oracleFee;\n }\n\n function getChainId() external view override returns (uint16) {\n return mockChainId;\n }\n\n function retryPayload(\n uint16 _srcChainId,\n bytes calldata _path,\n bytes calldata _payload\n ) external override {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n require(sp.payloadHash != bytes32(0), \"LayerZeroMock: no stored payload\");\n require(_payload.length == sp.payloadLength && keccak256(_payload) == sp.payloadHash, \"LayerZeroMock: invalid payload\");\n\n address dstAddress = sp.dstAddress;\n // empty the storedPayload\n sp.payloadLength = 0;\n sp.dstAddress = address(0);\n sp.payloadHash = bytes32(0);\n\n uint64 nonce = inboundNonce[_srcChainId][_path];\n\n ILayerZeroReceiver(dstAddress).lzReceive(_srcChainId, _path, nonce, _payload);\n emit PayloadCleared(_srcChainId, _path, nonce, dstAddress);\n }\n\n function hasStoredPayload(uint16 _srcChainId, bytes calldata _path) external view override returns (bool) {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n return sp.payloadHash != bytes32(0);\n }\n\n function getSendLibraryAddress(address) external view override returns (address) {\n return address(this);\n }\n\n function getReceiveLibraryAddress(address) external view override returns (address) {\n return address(this);\n }\n\n function isSendingPayload() external view override returns (bool) {\n return _send_entered_state == _ENTERED;\n }\n\n function isReceivingPayload() external view override returns (bool) {\n return _receive_entered_state == _ENTERED;\n }\n\n function getConfig(\n uint16, /*_version*/\n uint16, /*_chainId*/\n address, /*_ua*/\n uint /*_configType*/\n ) external pure override returns (bytes memory) {\n return \"\";\n }\n\n function getSendVersion(\n address /*_userApplication*/\n ) external pure override returns (uint16) {\n return 1;\n }\n\n function getReceiveVersion(\n address /*_userApplication*/\n ) external pure override returns (uint16) {\n return 1;\n }\n\n function setConfig(\n uint16, /*_version*/\n uint16, /*_chainId*/\n uint, /*_configType*/\n bytes memory /*_config*/\n ) external override {}\n\n function setSendVersion(\n uint16 /*version*/\n ) external override {}\n\n function setReceiveVersion(\n uint16 /*version*/\n ) external override {}\n\n function forceResumeReceive(uint16 _srcChainId, bytes calldata _path) external override {\n StoredPayload storage sp = storedPayload[_srcChainId][_path];\n // revert if no messages are cached. safeguard malicious UA behaviour\n require(sp.payloadHash != bytes32(0), \"LayerZeroMock: no stored payload\");\n require(sp.dstAddress == msg.sender, \"LayerZeroMock: invalid caller\");\n\n // empty the storedPayload\n sp.payloadLength = 0;\n sp.dstAddress = address(0);\n sp.payloadHash = bytes32(0);\n\n emit UaForceResumeReceive(_srcChainId, _path);\n\n // resume the receiving of msgs after we force clear the \"stuck\" msg\n _clearMsgQue(_srcChainId, _path);\n }\n\n // ------------------------------ Other Public/External Functions --------------------------------------------------\n\n function getLengthOfQueue(uint16 _srcChainId, bytes calldata _srcAddress) external view returns (uint) {\n return msgsToDeliver[_srcChainId][_srcAddress].length;\n }\n\n // used to simulate messages received get stored as a payload\n function blockNextMsg() external {\n nextMsgBlocked = true;\n }\n\n function setDestLzEndpoint(address destAddr, address lzEndpointAddr) external {\n lzEndpointLookup[destAddr] = lzEndpointAddr;\n }\n\n function setRelayerPrice(\n uint128 _dstPriceRatio,\n uint128 _dstGasPriceInWei,\n uint128 _dstNativeAmtCap,\n uint64 _baseGas,\n uint64 _gasPerByte\n ) external {\n relayerFeeConfig.dstPriceRatio = _dstPriceRatio;\n relayerFeeConfig.dstGasPriceInWei = _dstGasPriceInWei;\n relayerFeeConfig.dstNativeAmtCap = _dstNativeAmtCap;\n relayerFeeConfig.baseGas = _baseGas;\n relayerFeeConfig.gasPerByte = _gasPerByte;\n }\n\n function setProtocolFee(uint _zroFee, uint _nativeBP) external {\n protocolFeeConfig.zroFee = _zroFee;\n protocolFeeConfig.nativeBP = _nativeBP;\n }\n\n function setOracleFee(uint _oracleFee) external {\n oracleFee = _oracleFee;\n }\n\n function setDefaultAdapterParams(bytes memory _adapterParams) external {\n defaultAdapterParams = _adapterParams;\n }\n\n // --------------------- Internal Functions ---------------------\n // simulates the relayer pushing through the rest of the msgs that got delayed due to the stored payload\n function _clearMsgQue(uint16 _srcChainId, bytes calldata _path) internal {\n QueuedPayload[] storage msgs = msgsToDeliver[_srcChainId][_path];\n\n // warning, might run into gas issues trying to forward through a bunch of queued msgs\n while (msgs.length > 0) {\n QueuedPayload memory payload = msgs[msgs.length - 1];\n ILayerZeroReceiver(payload.dstAddress).lzReceive(_srcChainId, _path, payload.nonce, payload.payload);\n msgs.pop();\n }\n }\n\n function _getProtocolFees(\n bool _payInZro,\n uint _relayerFee,\n uint _oracleFee\n ) internal view returns (uint) {\n if (_payInZro) {\n return protocolFeeConfig.zroFee;\n } else {\n return ((_relayerFee + _oracleFee) * protocolFeeConfig.nativeBP) / 10000;\n }\n }\n\n function _getRelayerFee(\n uint16, /* _dstChainId */\n uint16, /* _outboundProofType */\n address, /* _userApplication */\n uint _payloadSize,\n bytes memory _adapterParams\n ) internal view returns (uint) {\n (uint16 txType, uint extraGas, uint dstNativeAmt, ) = LzLib.decodeAdapterParams(_adapterParams);\n uint totalRemoteToken; // = baseGas + extraGas + requiredNativeAmount\n if (txType == 2) {\n require(relayerFeeConfig.dstNativeAmtCap >= dstNativeAmt, \"LayerZeroMock: dstNativeAmt too large \");\n totalRemoteToken += dstNativeAmt;\n }\n // remoteGasTotal = dstGasPriceInWei * (baseGas + extraGas)\n uint remoteGasTotal = relayerFeeConfig.dstGasPriceInWei * (relayerFeeConfig.baseGas + extraGas);\n totalRemoteToken += remoteGasTotal;\n\n // tokenConversionRate = dstPrice / localPrice\n // basePrice = totalRemoteToken * tokenConversionRate\n uint basePrice = (totalRemoteToken * relayerFeeConfig.dstPriceRatio) / 10**10;\n\n // pricePerByte = (dstGasPriceInWei * gasPerBytes) * tokenConversionRate\n uint pricePerByte = (relayerFeeConfig.dstGasPriceInWei * relayerFeeConfig.gasPerByte * relayerFeeConfig.dstPriceRatio) / 10**10;\n\n return basePrice + _payloadSize * pricePerByte;\n }\n}\n" + }, + "@layerzerolabs/solidity-examples/contracts/lzApp/NonblockingLzApp.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./LzApp.sol\";\nimport \"../libraries/ExcessivelySafeCall.sol\";\n\n/*\n * the default LayerZero messaging behaviour is blocking, i.e. any failed message will block the channel\n * this abstract class try-catch all fail messages and store locally for future retry. hence, non-blocking\n * NOTE: if the srcAddress is not configured properly, it will still block the message pathway from (srcChainId, srcAddress)\n */\nabstract contract NonblockingLzApp is LzApp {\n using ExcessivelySafeCall for address;\n\n constructor(address _endpoint) LzApp(_endpoint) {}\n\n mapping(uint16 => mapping(bytes => mapping(uint64 => bytes32))) public failedMessages;\n\n event MessageFailed(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes _payload, bytes _reason);\n event RetryMessageSuccess(uint16 _srcChainId, bytes _srcAddress, uint64 _nonce, bytes32 _payloadHash);\n\n // overriding the virtual function in LzReceiver\n function _blockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual override {\n (bool success, bytes memory reason) = address(this).excessivelySafeCall(\n gasleft(),\n 150,\n abi.encodeWithSelector(this.nonblockingLzReceive.selector, _srcChainId, _srcAddress, _nonce, _payload)\n );\n if (!success) {\n _storeFailedMessage(_srcChainId, _srcAddress, _nonce, _payload, reason);\n }\n }\n\n function _storeFailedMessage(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload,\n bytes memory _reason\n ) internal virtual {\n failedMessages[_srcChainId][_srcAddress][_nonce] = keccak256(_payload);\n emit MessageFailed(_srcChainId, _srcAddress, _nonce, _payload, _reason);\n }\n\n function nonblockingLzReceive(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public virtual {\n // only internal transaction\n require(_msgSender() == address(this), \"NonblockingLzApp: caller must be LzApp\");\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n }\n\n //@notice override this function\n function _nonblockingLzReceive(\n uint16 _srcChainId,\n bytes memory _srcAddress,\n uint64 _nonce,\n bytes memory _payload\n ) internal virtual;\n\n function retryMessage(\n uint16 _srcChainId,\n bytes calldata _srcAddress,\n uint64 _nonce,\n bytes calldata _payload\n ) public payable virtual {\n // assert there is message to retry\n bytes32 payloadHash = failedMessages[_srcChainId][_srcAddress][_nonce];\n require(payloadHash != bytes32(0), \"NonblockingLzApp: no stored message\");\n require(keccak256(_payload) == payloadHash, \"NonblockingLzApp: invalid payload\");\n // clear the stored message\n failedMessages[_srcChainId][_srcAddress][_nonce] = bytes32(0);\n // execute the message. revert if it fails again\n _nonblockingLzReceive(_srcChainId, _srcAddress, _nonce, _payload);\n emit RetryMessageSuccess(_srcChainId, _srcAddress, _nonce, payloadHash);\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./OwnableUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership} and {acceptOwnership}.\n *\n * This module is used through inheritance. It will make available all functions\n * from parent (Ownable).\n */\nabstract contract Ownable2StepUpgradeable is Initializable, OwnableUpgradeable {\n function __Ownable2Step_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable2Step_init_unchained() internal onlyInitializing {\n }\n address private _pendingOwner;\n\n event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the pending owner.\n */\n function pendingOwner() public view virtual returns (address) {\n return _pendingOwner;\n }\n\n /**\n * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual override onlyOwner {\n _pendingOwner = newOwner;\n emit OwnershipTransferStarted(owner(), newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual override {\n delete _pendingOwner;\n super._transferOwnership(newOwner);\n }\n\n /**\n * @dev The new owner accepts the ownership transfer.\n */\n function acceptOwnership() external {\n address sender = _msgSender();\n require(pendingOwner() == sender, \"Ownable2Step: caller is not the new owner\");\n _transferOwnership(sender);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n function __Ownable_init() internal onlyInitializing {\n __Ownable_init_unchained();\n }\n\n function __Ownable_init_unchained() internal onlyInitializing {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n}\n" + }, + "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.1) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts.\n *\n * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a\n * constructor.\n *\n * Emits an {Initialized} event.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * A reinitializer may be used after the original initialization step. This is essential to configure modules that\n * are added through upgrades and that require initialization.\n *\n * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`\n * cannot be nested. If one is invoked in the context of another, execution will revert.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n *\n * WARNING: setting the version to 255 will prevent any future reinitialization.\n *\n * Emits an {Initialized} event.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n *\n * Emits an {Initialized} event the first time it is successfully executed.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n\n /**\n * @dev Returns the highest version that has been initialized. See {reinitializer}.\n */\n function _getInitializedVersion() internal view returns (uint8) {\n return _initialized;\n }\n\n /**\n * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.\n */\n function _isInitializing() internal view returns (bool) {\n return _initializing;\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResultFromTarget(target, success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling\n * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.\n *\n * _Available since v4.8._\n */\n function verifyCallResultFromTarget(\n address target,\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n if (success) {\n if (returndata.length == 0) {\n // only check isContract if the call was successful and the return data is empty\n // otherwise we already know that it was a contract\n require(isContract(target), \"Address: call to non-contract\");\n }\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n /**\n * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason or using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n _revert(returndata, errorMessage);\n }\n }\n\n function _revert(bytes memory returndata, string memory errorMessage) private pure {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n}\n" + }, + "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n" + }, + "@openzeppelin/contracts/access/AccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IAccessControl.sol\";\nimport \"../utils/Context.sol\";\nimport \"../utils/Strings.sol\";\nimport \"../utils/introspection/ERC165.sol\";\n\n/**\n * @dev Contract module that allows children to implement role-based access\n * control mechanisms. This is a lightweight version that doesn't allow enumerating role\n * members except through off-chain means by accessing the contract event logs. Some\n * applications may benefit from on-chain enumerability, for those cases see\n * {AccessControlEnumerable}.\n *\n * Roles are referred to by their `bytes32` identifier. These should be exposed\n * in the external API and be unique. The best way to achieve this is by\n * using `public constant` hash digests:\n *\n * ```\n * bytes32 public constant MY_ROLE = keccak256(\"MY_ROLE\");\n * ```\n *\n * Roles can be used to represent a set of permissions. To restrict access to a\n * function call, use {hasRole}:\n *\n * ```\n * function foo() public {\n * require(hasRole(MY_ROLE, msg.sender));\n * ...\n * }\n * ```\n *\n * Roles can be granted and revoked dynamically via the {grantRole} and\n * {revokeRole} functions. Each role has an associated admin role, and only\n * accounts that have a role's admin role can call {grantRole} and {revokeRole}.\n *\n * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means\n * that only accounts with this role will be able to grant or revoke other\n * roles. More complex role relationships can be created by using\n * {_setRoleAdmin}.\n *\n * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to\n * grant and revoke this role. Extra precautions should be taken to secure\n * accounts that have been granted it.\n */\nabstract contract AccessControl is Context, IAccessControl, ERC165 {\n struct RoleData {\n mapping(address => bool) members;\n bytes32 adminRole;\n }\n\n mapping(bytes32 => RoleData) private _roles;\n\n bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;\n\n /**\n * @dev Modifier that checks that an account has a specific role. Reverts\n * with a standardized message including the required role.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n *\n * _Available since v4.1._\n */\n modifier onlyRole(bytes32 role) {\n _checkRole(role);\n _;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) public view virtual override returns (bool) {\n return _roles[role].members[account];\n }\n\n /**\n * @dev Revert with a standard message if `_msgSender()` is missing `role`.\n * Overriding this function changes the behavior of the {onlyRole} modifier.\n *\n * Format of the revert message is described in {_checkRole}.\n *\n * _Available since v4.6._\n */\n function _checkRole(bytes32 role) internal view virtual {\n _checkRole(role, _msgSender());\n }\n\n /**\n * @dev Revert with a standard message if `account` is missing `role`.\n *\n * The format of the revert reason is given by the following regular expression:\n *\n * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/\n */\n function _checkRole(bytes32 role, address account) internal view virtual {\n if (!hasRole(role, account)) {\n revert(\n string(\n abi.encodePacked(\n \"AccessControl: account \",\n Strings.toHexString(account),\n \" is missing role \",\n Strings.toHexString(uint256(role), 32)\n )\n )\n );\n }\n }\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) {\n return _roles[role].adminRole;\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleGranted} event.\n */\n function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _grantRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n *\n * May emit a {RoleRevoked} event.\n */\n function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {\n _revokeRole(role, account);\n }\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been revoked `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n *\n * May emit a {RoleRevoked} event.\n */\n function renounceRole(bytes32 role, address account) public virtual override {\n require(account == _msgSender(), \"AccessControl: can only renounce roles for self\");\n\n _revokeRole(role, account);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event. Note that unlike {grantRole}, this function doesn't perform any\n * checks on the calling account.\n *\n * May emit a {RoleGranted} event.\n *\n * [WARNING]\n * ====\n * This function should only be called from the constructor when setting\n * up the initial roles for the system.\n *\n * Using this function in any other way is effectively circumventing the admin\n * system imposed by {AccessControl}.\n * ====\n *\n * NOTE: This function is deprecated in favor of {_grantRole}.\n */\n function _setupRole(bytes32 role, address account) internal virtual {\n _grantRole(role, account);\n }\n\n /**\n * @dev Sets `adminRole` as ``role``'s admin role.\n *\n * Emits a {RoleAdminChanged} event.\n */\n function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {\n bytes32 previousAdminRole = getRoleAdmin(role);\n _roles[role].adminRole = adminRole;\n emit RoleAdminChanged(role, previousAdminRole, adminRole);\n }\n\n /**\n * @dev Grants `role` to `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleGranted} event.\n */\n function _grantRole(bytes32 role, address account) internal virtual {\n if (!hasRole(role, account)) {\n _roles[role].members[account] = true;\n emit RoleGranted(role, account, _msgSender());\n }\n }\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * Internal function without access restriction.\n *\n * May emit a {RoleRevoked} event.\n */\n function _revokeRole(bytes32 role, address account) internal virtual {\n if (hasRole(role, account)) {\n _roles[role].members[account] = false;\n emit RoleRevoked(role, account, _msgSender());\n }\n }\n}\n" + }, + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "@openzeppelin/contracts/access/Ownable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n address private _owner;\n\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Initializes the contract setting the deployer as the initial owner.\n */\n constructor() {\n _transferOwnership(_msgSender());\n }\n\n /**\n * @dev Throws if called by any account other than the owner.\n */\n modifier onlyOwner() {\n _checkOwner();\n _;\n }\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() public view virtual returns (address) {\n return _owner;\n }\n\n /**\n * @dev Throws if the sender is not the owner.\n */\n function _checkOwner() internal view virtual {\n require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n }\n\n /**\n * @dev Leaves the contract without owner. It will not be possible to call\n * `onlyOwner` functions anymore. Can only be called by the current owner.\n *\n * NOTE: Renouncing ownership will leave the contract without an owner,\n * thereby removing any functionality that is only available to the owner.\n */\n function renounceOwnership() public virtual onlyOwner {\n _transferOwnership(address(0));\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) public virtual onlyOwner {\n require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n _transferOwnership(newOwner);\n }\n\n /**\n * @dev Transfers ownership of the contract to a new account (`newOwner`).\n * Internal function without access restriction.\n */\n function _transferOwnership(address newOwner) internal virtual {\n address oldOwner = _owner;\n _owner = newOwner;\n emit OwnershipTransferred(oldOwner, newOwner);\n }\n}\n" + }, + "@openzeppelin/contracts/security/Pausable.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n /**\n * @dev Emitted when the pause is triggered by `account`.\n */\n event Paused(address account);\n\n /**\n * @dev Emitted when the pause is lifted by `account`.\n */\n event Unpaused(address account);\n\n bool private _paused;\n\n /**\n * @dev Initializes the contract in unpaused state.\n */\n constructor() {\n _paused = false;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is not paused.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n modifier whenNotPaused() {\n _requireNotPaused();\n _;\n }\n\n /**\n * @dev Modifier to make a function callable only when the contract is paused.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n modifier whenPaused() {\n _requirePaused();\n _;\n }\n\n /**\n * @dev Returns true if the contract is paused, and false otherwise.\n */\n function paused() public view virtual returns (bool) {\n return _paused;\n }\n\n /**\n * @dev Throws if the contract is paused.\n */\n function _requireNotPaused() internal view virtual {\n require(!paused(), \"Pausable: paused\");\n }\n\n /**\n * @dev Throws if the contract is not paused.\n */\n function _requirePaused() internal view virtual {\n require(paused(), \"Pausable: not paused\");\n }\n\n /**\n * @dev Triggers stopped state.\n *\n * Requirements:\n *\n * - The contract must not be paused.\n */\n function _pause() internal virtual whenNotPaused {\n _paused = true;\n emit Paused(_msgSender());\n }\n\n /**\n * @dev Returns to normal state.\n *\n * Requirements:\n *\n * - The contract must be paused.\n */\n function _unpause() internal virtual whenPaused {\n _paused = false;\n emit Unpaused(_msgSender());\n }\n}\n" + }, + "@openzeppelin/contracts/security/ReentrancyGuard.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuard {\n // Booleans are more expensive than uint256 or any type that takes up a full\n // word because each write operation emits an extra SLOAD to first read the\n // slot's contents, replace the bits taken up by the boolean, and then write\n // back. This is the compiler's defense against contract upgrades and\n // pointer aliasing, and it cannot be disabled.\n\n // The values being non-zero value makes deployment a bit more expensive,\n // but in exchange the refund on every call to nonReentrant will be lower in\n // amount. Since refunds are capped to a percentage of the total\n // transaction's gas, it is best to keep them low in cases like this one, to\n // increase the likelihood of the full refund coming into effect.\n uint256 private constant _NOT_ENTERED = 1;\n uint256 private constant _ENTERED = 2;\n\n uint256 private _status;\n\n constructor() {\n _status = _NOT_ENTERED;\n }\n\n /**\n * @dev Prevents a contract from calling itself, directly or indirectly.\n * Calling a `nonReentrant` function from another `nonReentrant`\n * function is not supported. It is possible to prevent this from happening\n * by making the `nonReentrant` function external, and making it call a\n * `private` function that does the actual work.\n */\n modifier nonReentrant() {\n _nonReentrantBefore();\n _;\n _nonReentrantAfter();\n }\n\n function _nonReentrantBefore() private {\n // On the first call to nonReentrant, _status will be _NOT_ENTERED\n require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n // Any calls to nonReentrant after this point will fail\n _status = _ENTERED;\n }\n\n function _nonReentrantAfter() private {\n // By storing the original value once again, a refund is triggered (see\n // https://eips.ethereum.org/EIPS/eip-2200)\n _status = _NOT_ENTERED;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Context.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/ERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165 is IERC165 {\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165).interfaceId;\n }\n}\n" + }, + "@openzeppelin/contracts/utils/introspection/IERC165.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n" + }, + "@openzeppelin/contracts/utils/math/Math.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n enum Rounding {\n Down, // Toward negative infinity\n Up, // Toward infinity\n Zero // Toward zero\n }\n\n /**\n * @dev Returns the largest of two numbers.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a > b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n /**\n * @dev Returns the average of two numbers. The result is rounded towards\n * zero.\n */\n function average(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b) / 2 can overflow.\n return (a & b) + (a ^ b) / 2;\n }\n\n /**\n * @dev Returns the ceiling of the division of two numbers.\n *\n * This differs from standard division with `/` in that it rounds up instead\n * of rounding down.\n */\n function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n // (a + b - 1) / b can overflow on addition, so we distribute.\n return a == 0 ? 0 : (a - 1) / b + 1;\n }\n\n /**\n * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n * with further edits by Uniswap Labs also under MIT license.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator\n ) internal pure returns (uint256 result) {\n unchecked {\n // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n // variables such that product = prod1 * 2^256 + prod0.\n uint256 prod0; // Least significant 256 bits of the product\n uint256 prod1; // Most significant 256 bits of the product\n assembly {\n let mm := mulmod(x, y, not(0))\n prod0 := mul(x, y)\n prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n }\n\n // Handle non-overflow cases, 256 by 256 division.\n if (prod1 == 0) {\n return prod0 / denominator;\n }\n\n // Make sure the result is less than 2^256. Also prevents denominator == 0.\n require(denominator > prod1);\n\n ///////////////////////////////////////////////\n // 512 by 256 division.\n ///////////////////////////////////////////////\n\n // Make division exact by subtracting the remainder from [prod1 prod0].\n uint256 remainder;\n assembly {\n // Compute remainder using mulmod.\n remainder := mulmod(x, y, denominator)\n\n // Subtract 256 bit number from 512 bit number.\n prod1 := sub(prod1, gt(remainder, prod0))\n prod0 := sub(prod0, remainder)\n }\n\n // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n // See https://cs.stackexchange.com/q/138556/92363.\n\n // Does not overflow because the denominator cannot be zero at this stage in the function.\n uint256 twos = denominator & (~denominator + 1);\n assembly {\n // Divide denominator by twos.\n denominator := div(denominator, twos)\n\n // Divide [prod1 prod0] by twos.\n prod0 := div(prod0, twos)\n\n // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n twos := add(div(sub(0, twos), twos), 1)\n }\n\n // Shift in bits from prod1 into prod0.\n prod0 |= prod1 * twos;\n\n // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n // four bits. That is, denominator * inv = 1 mod 2^4.\n uint256 inverse = (3 * denominator) ^ 2;\n\n // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n // in modular arithmetic, doubling the correct bits in each step.\n inverse *= 2 - denominator * inverse; // inverse mod 2^8\n inverse *= 2 - denominator * inverse; // inverse mod 2^16\n inverse *= 2 - denominator * inverse; // inverse mod 2^32\n inverse *= 2 - denominator * inverse; // inverse mod 2^64\n inverse *= 2 - denominator * inverse; // inverse mod 2^128\n inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n // is no longer required.\n result = prod0 * inverse;\n return result;\n }\n }\n\n /**\n * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n */\n function mulDiv(\n uint256 x,\n uint256 y,\n uint256 denominator,\n Rounding rounding\n ) internal pure returns (uint256) {\n uint256 result = mulDiv(x, y, denominator);\n if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n result += 1;\n }\n return result;\n }\n\n /**\n * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n *\n * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n */\n function sqrt(uint256 a) internal pure returns (uint256) {\n if (a == 0) {\n return 0;\n }\n\n // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n //\n // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n //\n // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n //\n // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n uint256 result = 1 << (log2(a) >> 1);\n\n // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n // into the expected uint128 result.\n unchecked {\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n result = (result + a / result) >> 1;\n return min(result, a / result);\n }\n }\n\n /**\n * @notice Calculates sqrt(a), following the selected rounding direction.\n */\n function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = sqrt(a);\n return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 2, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 128;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 64;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 32;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 16;\n }\n if (value >> 8 > 0) {\n value >>= 8;\n result += 8;\n }\n if (value >> 4 > 0) {\n value >>= 4;\n result += 4;\n }\n if (value >> 2 > 0) {\n value >>= 2;\n result += 2;\n }\n if (value >> 1 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log2(value);\n return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 10, rounded down, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >= 10**64) {\n value /= 10**64;\n result += 64;\n }\n if (value >= 10**32) {\n value /= 10**32;\n result += 32;\n }\n if (value >= 10**16) {\n value /= 10**16;\n result += 16;\n }\n if (value >= 10**8) {\n value /= 10**8;\n result += 8;\n }\n if (value >= 10**4) {\n value /= 10**4;\n result += 4;\n }\n if (value >= 10**2) {\n value /= 10**2;\n result += 2;\n }\n if (value >= 10**1) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log10(value);\n return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n }\n }\n\n /**\n * @dev Return the log in base 256, rounded down, of a positive value.\n * Returns 0 if given 0.\n *\n * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n */\n function log256(uint256 value) internal pure returns (uint256) {\n uint256 result = 0;\n unchecked {\n if (value >> 128 > 0) {\n value >>= 128;\n result += 16;\n }\n if (value >> 64 > 0) {\n value >>= 64;\n result += 8;\n }\n if (value >> 32 > 0) {\n value >>= 32;\n result += 4;\n }\n if (value >> 16 > 0) {\n value >>= 16;\n result += 2;\n }\n if (value >> 8 > 0) {\n result += 1;\n }\n }\n return result;\n }\n\n /**\n * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n * Returns 0 if given 0.\n */\n function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n unchecked {\n uint256 result = log256(value);\n return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n }\n }\n}\n" + }, + "@openzeppelin/contracts/utils/Strings.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n unchecked {\n uint256 length = Math.log10(value) + 1;\n string memory buffer = new string(length);\n uint256 ptr;\n /// @solidity memory-safe-assembly\n assembly {\n ptr := add(buffer, add(32, length))\n }\n while (true) {\n ptr--;\n /// @solidity memory-safe-assembly\n assembly {\n mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n }\n value /= 10;\n if (value == 0) break;\n }\n return buffer;\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n unchecked {\n return toHexString(value, Math.log256(value) + 1);\n }\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n" + }, + "@venusprotocol/solidity-utilities/contracts/validators.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\n/// @notice Thrown if the supplied address is a zero address where it is not allowed\nerror ZeroAddressNotAllowed();\n\n/// @notice Thrown if the supplied value is 0 where it is not allowed\nerror ZeroValueNotAllowed();\n\n/// @notice Checks if the provided address is nonzero, reverts otherwise\n/// @param address_ Address to check\n/// @custom:error ZeroAddressNotAllowed is thrown if the provided address is a zero address\nfunction ensureNonzeroAddress(address address_) pure {\n if (address_ == address(0)) {\n revert ZeroAddressNotAllowed();\n }\n}\n\n/// @notice Checks if the provided value is nonzero, reverts otherwise\n/// @param value_ Value to check\n/// @custom:error ZeroValueNotAllowed is thrown if the provided value is 0\nfunction ensureNonzeroValue(uint256 value_) pure {\n if (value_ == 0) {\n revert ZeroValueNotAllowed();\n }\n}\n" + }, + "contracts/Cross-chain/BaseOmnichainControllerDest.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npragma solidity 0.8.25;\n\nimport { NonblockingLzApp } from \"@layerzerolabs/solidity-examples/contracts/lzApp/NonblockingLzApp.sol\";\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title BaseOmnichainControllerDest\n * @author Venus\n * @dev This contract is the base for the Omnichain controller destination contract\n * It provides functionality related to daily command limits and pausability\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\nabstract contract BaseOmnichainControllerDest is NonblockingLzApp, Pausable {\n /**\n * @notice Maximum daily limit for receiving commands from Binance chain\n */\n uint256 public maxDailyReceiveLimit;\n\n /**\n * @notice Total received commands within the last 24-hour window from Binance chain\n */\n uint256 public last24HourCommandsReceived;\n\n /**\n * @notice Timestamp when the last 24-hour window started from Binance chain\n */\n uint256 public last24HourReceiveWindowStart;\n\n /**\n * @notice Emitted when the maximum daily limit for receiving command from Binance chain is modified\n */\n event SetMaxDailyReceiveLimit(uint256 oldMaxLimit, uint256 newMaxLimit);\n\n constructor(address endpoint_) NonblockingLzApp(endpoint_) {\n ensureNonzeroAddress(endpoint_);\n }\n\n /**\n * @notice Sets the maximum daily limit for receiving commands\n * @param limit_ Number of commands\n * @custom:access Only Owner\n * @custom:event Emits SetMaxDailyReceiveLimit with old and new limit\n */\n function setMaxDailyReceiveLimit(uint256 limit_) external onlyOwner {\n emit SetMaxDailyReceiveLimit(maxDailyReceiveLimit, limit_);\n maxDailyReceiveLimit = limit_;\n }\n\n /**\n * @notice Triggers the paused state of the controller\n * @custom:access Only owner\n */\n function pause() external onlyOwner {\n _pause();\n }\n\n /**\n * @notice Triggers the resume state of the controller\n * @custom:access Only owner\n */\n function unpause() external onlyOwner {\n _unpause();\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishappening\n */\n function renounceOwnership() public override {}\n\n /**\n * @notice Check eligibility to receive commands\n * @param noOfCommands_ Number of commands to be received\n */\n function _isEligibleToReceive(uint256 noOfCommands_) internal {\n uint256 currentBlockTimestamp = block.timestamp;\n\n // Load values for the 24-hour window checks for receiving\n uint256 receivedInWindow = last24HourCommandsReceived;\n\n // Check if the time window has changed (more than 24 hours have passed)\n if (currentBlockTimestamp - last24HourReceiveWindowStart > 1 days) {\n receivedInWindow = noOfCommands_;\n last24HourReceiveWindowStart = currentBlockTimestamp;\n } else {\n receivedInWindow += noOfCommands_;\n }\n\n // Revert if the received amount exceeds the daily limit\n require(receivedInWindow <= maxDailyReceiveLimit, \"Daily Transaction Limit Exceeded\");\n\n // Update the received amount for the 24-hour window\n last24HourCommandsReceived = receivedInWindow;\n }\n}\n" + }, + "contracts/Cross-chain/BaseOmnichainControllerSrc.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\n\npragma solidity 0.8.25;\n\nimport { Pausable } from \"@openzeppelin/contracts/security/Pausable.sol\";\nimport { Ownable } from \"@openzeppelin/contracts/access/Ownable.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { IAccessControlManagerV8 } from \"./../Governance/IAccessControlManagerV8.sol\";\n\n/**\n * @title BaseOmnichainControllerSrc\n * @dev This contract is the base for the Omnichain controller source contracts.\n * It provides functionality related to daily command limits and pausability.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract BaseOmnichainControllerSrc is Ownable, Pausable {\n /**\n * @notice ACM (Access Control Manager) contract address\n */\n address public accessControlManager;\n\n /**\n * @notice Maximum daily limit for commands from the local chain\n */\n mapping(uint16 => uint256) public chainIdToMaxDailyLimit;\n\n /**\n * @notice Total commands transferred within the last 24-hour window from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourCommandsSent;\n\n /**\n * @notice Timestamp when the last 24-hour window started from the local chain\n */\n mapping(uint16 => uint256) public chainIdToLast24HourWindowStart;\n /**\n * @notice Timestamp when the last proposal sent from the local chain to dest chain\n */\n mapping(uint16 => uint256) public chainIdToLastProposalSentTimestamp;\n\n /**\n * @notice Emitted when the maximum daily limit of commands from the local chain is modified\n */\n event SetMaxDailyLimit(uint16 indexed chainId, uint256 oldMaxLimit, uint256 newMaxLimit);\n /*\n * @notice Emitted when the address of ACM is updated\n */\n event NewAccessControlManager(address indexed oldAccessControlManager, address indexed newAccessControlManager);\n\n constructor(address accessControlManager_) {\n ensureNonzeroAddress(accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Sets the limit of daily (24 Hour) command amount\n * @param chainId_ Destination chain id\n * @param limit_ Number of commands\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetMaxDailyLimit with old and new limit and its corresponding chain id\n */\n function setMaxDailyLimit(uint16 chainId_, uint256 limit_) external {\n _ensureAllowed(\"setMaxDailyLimit(uint16,uint256)\");\n emit SetMaxDailyLimit(chainId_, chainIdToMaxDailyLimit[chainId_], limit_);\n chainIdToMaxDailyLimit[chainId_] = limit_;\n }\n\n /**\n * @notice Triggers the paused state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function pause() external {\n _ensureAllowed(\"pause()\");\n _pause();\n }\n\n /**\n * @notice Triggers the resume state of the controller\n * @custom:access Controlled by AccessControlManager\n */\n function unpause() external {\n _ensureAllowed(\"unpause()\");\n _unpause();\n }\n\n /**\n * @notice Sets the address of Access Control Manager (ACM)\n * @param accessControlManager_ The new address of the Access Control Manager\n * @custom:access Only owner\n * @custom:event Emits NewAccessControlManager with old and new access control manager addresses\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n ensureNonzeroAddress(accessControlManager_);\n emit NewAccessControlManager(accessControlManager, accessControlManager_);\n accessControlManager = accessControlManager_;\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishap\n */\n function renounceOwnership() public override {}\n\n /**\n * @notice Check eligibility to send commands\n * @param dstChainId_ Destination chain id\n * @param noOfCommands_ Number of commands to send\n */\n function _isEligibleToSend(uint16 dstChainId_, uint256 noOfCommands_) internal {\n // Load values for the 24-hour window checks\n uint256 currentBlockTimestamp = block.timestamp;\n uint256 lastDayWindowStart = chainIdToLast24HourWindowStart[dstChainId_];\n uint256 commandsSentInWindow = chainIdToLast24HourCommandsSent[dstChainId_];\n uint256 maxDailyLimit = chainIdToMaxDailyLimit[dstChainId_];\n uint256 lastProposalSentTimestamp = chainIdToLastProposalSentTimestamp[dstChainId_];\n\n // Check if the time window has changed (more than 24 hours have passed)\n if (currentBlockTimestamp - lastDayWindowStart > 1 days) {\n commandsSentInWindow = noOfCommands_;\n chainIdToLast24HourWindowStart[dstChainId_] = currentBlockTimestamp;\n } else {\n commandsSentInWindow += noOfCommands_;\n }\n\n // Revert if the amount exceeds the daily limit\n require(commandsSentInWindow <= maxDailyLimit, \"Daily Transaction Limit Exceeded\");\n // Revert if the last proposal is already sent in current block i.e multiple proposals cannot be sent within the same block.timestamp\n require(lastProposalSentTimestamp != currentBlockTimestamp, \"Multiple bridging in a proposal\");\n\n // Update the amount for the 24-hour window\n chainIdToLast24HourCommandsSent[dstChainId_] = commandsSentInWindow;\n // Update the last sent proposal timestamp\n chainIdToLastProposalSentTimestamp[dstChainId_] = currentBlockTimestamp;\n }\n\n /**\n * @notice Ensure that the caller has permission to execute a specific function\n * @param functionSig_ Function signature to be checked for permission\n */\n function _ensureAllowed(string memory functionSig_) internal view {\n require(\n IAccessControlManagerV8(accessControlManager).isAllowedToCall(msg.sender, functionSig_),\n \"access denied\"\n );\n }\n}\n" + }, + "contracts/Cross-chain/interfaces/IOmnichainGovernanceExecutor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.25;\n\ninterface IOmnichainGovernanceExecutor {\n /**\n * @notice Transfers ownership of the contract to the specified address\n * @param addr The address to which ownership will be transferred\n */\n function transferOwnership(address addr) external;\n\n /**\n * @notice Sets the source message sender address\n * @param srcChainId_ The LayerZero id of a source chain\n * @param srcAddress_ The address of the contract on the source chain\n */\n function setTrustedRemoteAddress(uint16 srcChainId_, bytes calldata srcAddress_) external;\n}\n" + }, + "contracts/Cross-chain/interfaces/ITimelock.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\n/**\n * @title ITimelock\n * @author Venus\n * @dev Interface for Timelock contract\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\ninterface ITimelock {\n /**\n * @notice Delay period for the transaction queue\n */\n function delay() external view returns (uint256);\n\n /**\n * @notice Required period to execute a proposal transaction\n */\n function GRACE_PERIOD() external view returns (uint256);\n\n /**\n * @notice Method for accepting a proposed admin\n */\n function acceptAdmin() external;\n\n /**\n * @notice Method to propose a new admin authorized to call timelock functions. This should be the Governor Contract.\n */\n function setPendingAdmin(address pendingAdmin) external;\n\n /**\n * @notice Show mapping of queued transactions\n * @param hash Transaction hash\n */\n function queuedTransactions(bytes32 hash) external view returns (bool);\n\n /**\n * @notice Called for each action when queuing a proposal\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Hash of the queued transaction\n */\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external returns (bytes32);\n\n /**\n * @notice Called to cancel a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n */\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external;\n\n /**\n * @notice Called to execute a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Result of function call\n */\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) external payable returns (bytes memory);\n}\n" + }, + "contracts/Cross-chain/OmnichainExecutorOwner.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { AccessControlledV8 } from \"../Governance/AccessControlledV8.sol\";\nimport { IOmnichainGovernanceExecutor } from \"./interfaces/IOmnichainGovernanceExecutor.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title OmnichainExecutorOwner\n * @author Venus\n * @notice OmnichainProposalSender contract acts as a governance and access control mechanism,\n * allowing owner to upsert signature of OmnichainGovernanceExecutor contract,\n * also contains function to transfer the ownership of contract as well.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract OmnichainExecutorOwner is AccessControlledV8 {\n /**\n * @custom:oz-upgrades-unsafe-allow state-variable-immutable\n */\n IOmnichainGovernanceExecutor public immutable OMNICHAIN_GOVERNANCE_EXECUTOR;\n\n /**\n * @notice Stores function signature corresponding to their 4 bytes hash value\n */\n mapping(bytes4 => string) public functionRegistry;\n\n /**\n * @notice Event emitted when function registry updated\n */\n event FunctionRegistryChanged(string indexed signature, bool active);\n\n /// @custom:oz-upgrades-unsafe-allow constructor\n constructor(address omnichainGovernanceExecutor_) {\n require(omnichainGovernanceExecutor_ != address(0), \"Address must not be zero\");\n OMNICHAIN_GOVERNANCE_EXECUTOR = IOmnichainGovernanceExecutor(omnichainGovernanceExecutor_);\n _disableInitializers();\n }\n\n /**\n * @notice Initialize the contract\n * @param accessControlManager_ Address of access control manager\n */\n function initialize(address accessControlManager_) external initializer {\n require(accessControlManager_ != address(0), \"Address must not be zero\");\n __AccessControlled_init(accessControlManager_);\n }\n\n /**\n * @notice Sets the source message sender address\n * @param srcChainId_ The LayerZero id of a source chain\n * @param srcAddress_ The address of the contract on the source chain\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetTrustedRemoteAddress with source chain Id and source address\n */\n function setTrustedRemoteAddress(uint16 srcChainId_, bytes calldata srcAddress_) external {\n _checkAccessAllowed(\"setTrustedRemoteAddress(uint16,bytes)\");\n require(srcChainId_ != 0, \"ChainId must not be zero\");\n ensureNonzeroAddress(address(uint160(bytes20(srcAddress_))));\n require(srcAddress_.length == 20, \"Source address must be 20 bytes long\");\n OMNICHAIN_GOVERNANCE_EXECUTOR.setTrustedRemoteAddress(srcChainId_, srcAddress_);\n }\n\n /**\n * @notice Invoked when called function does not exist in the contract\n * @param data_ Calldata containing the encoded function call\n * @return Result of function call\n * @custom:access Controlled by Access Control Manager\n */\n fallback(bytes calldata data_) external returns (bytes memory) {\n string memory fun = functionRegistry[msg.sig];\n require(bytes(fun).length != 0, \"Function not found\");\n _checkAccessAllowed(fun);\n (bool ok, bytes memory res) = address(OMNICHAIN_GOVERNANCE_EXECUTOR).call(data_);\n require(ok, \"call failed\");\n return res;\n }\n\n /**\n * @notice A registry of functions that are allowed to be executed from proposals\n * @param signatures_ Function signature to be added or removed\n * @param active_ bool value, should be true to add function\n * @custom:access Only owner\n */\n function upsertSignature(string[] calldata signatures_, bool[] calldata active_) external onlyOwner {\n uint256 signatureLength = signatures_.length;\n require(signatureLength == active_.length, \"Input arrays must have the same length\");\n for (uint256 i; i < signatureLength; ++i) {\n bytes4 sigHash = bytes4(keccak256(bytes(signatures_[i])));\n bytes memory signature = bytes(functionRegistry[sigHash]);\n if (active_[i] && signature.length == 0) {\n functionRegistry[sigHash] = signatures_[i];\n emit FunctionRegistryChanged(signatures_[i], true);\n } else if (!active_[i] && signature.length != 0) {\n delete functionRegistry[sigHash];\n emit FunctionRegistryChanged(signatures_[i], false);\n }\n }\n }\n\n /**\n * @notice This function transfer the ownership of the executor from this contract to new owner\n * @param newOwner_ New owner of the governanceExecutor\n * @custom:access Controlled by AccessControlManager\n */\n\n function transferBridgeOwnership(address newOwner_) external {\n _checkAccessAllowed(\"transferBridgeOwnership(address)\");\n require(newOwner_ != address(0), \"Address must not be zero\");\n OMNICHAIN_GOVERNANCE_EXECUTOR.transferOwnership(newOwner_);\n }\n\n /**\n * @notice Empty implementation of renounce ownership to avoid any mishappening\n */\n function renounceOwnership() public virtual override {}\n}\n" + }, + "contracts/Cross-chain/OmnichainGovernanceExecutor.sol": { + "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.25;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { BytesLib } from \"@layerzerolabs/solidity-examples/contracts/libraries/BytesLib.sol\";\nimport { ExcessivelySafeCall } from \"@layerzerolabs/solidity-examples/contracts/libraries/ExcessivelySafeCall.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { BaseOmnichainControllerDest } from \"./BaseOmnichainControllerDest.sol\";\nimport { ITimelock } from \"./interfaces/ITimelock.sol\";\n\n/**\n * @title OmnichainGovernanceExecutor\n * @notice Executes the proposal transactions sent from the main chain\n * @dev The owner of this contract controls LayerZero configuration. When used in production the owner will be OmnichainExecutor\n * This implementation is non-blocking, meaning the failed messages will not block the future messages from the source.\n * For the blocking behavior, derive the contract from LzApp.\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\ncontract OmnichainGovernanceExecutor is ReentrancyGuard, BaseOmnichainControllerDest {\n using BytesLib for bytes;\n using ExcessivelySafeCall for address;\n\n enum ProposalType {\n NORMAL,\n FASTTRACK,\n CRITICAL\n }\n\n struct Proposal {\n /** Unique id for looking up a proposal */\n uint256 id;\n /** The timestamp that the proposal will be available for execution, set once the vote succeeds */\n uint256 eta;\n /** The ordered list of target addresses for calls to be made */\n address[] targets;\n /** The ordered list of values (i.e. msg.value) to be passed to the calls to be made */\n uint256[] values;\n /** The ordered list of function signatures to be called */\n string[] signatures;\n /** The ordered list of calldata to be passed to each call */\n bytes[] calldatas;\n /** Flag marking whether the proposal has been canceled */\n bool canceled;\n /** Flag marking whether the proposal has been executed */\n bool executed;\n /** The type of the proposal */\n uint8 proposalType;\n }\n /*\n * @notice Possible states that a proposal may be in\n */\n enum ProposalState {\n Canceled,\n Queued,\n Executed\n }\n\n /**\n * @notice A privileged role that can cancel any proposal\n */\n address public guardian;\n\n /**\n * @notice Stores BNB chain layerzero endpoint id\n */\n uint16 public srcChainId;\n\n /**\n * @notice Last proposal count received\n */\n uint256 public lastProposalReceived;\n\n /**\n * @notice The official record of all proposals ever proposed\n */\n mapping(uint256 => Proposal) public proposals;\n\n /**\n * @notice Mapping containing Timelock addresses for each proposal type\n */\n mapping(uint256 => ITimelock) public proposalTimelocks;\n\n /**\n * @notice Represents queue state of proposal\n */\n mapping(uint256 => bool) public queued;\n\n /**\n * @notice Emitted when proposal is received\n */\n event ProposalReceived(\n uint256 indexed proposalId,\n address[] targets,\n uint256[] values,\n string[] signatures,\n bytes[] calldatas,\n uint8 proposalType\n );\n\n /**\n * @notice Emitted when proposal is queued\n */\n event ProposalQueued(uint256 indexed id, uint256 eta);\n\n /**\n * Emitted when proposal executed\n */\n event ProposalExecuted(uint256 indexed id);\n\n /**\n * @notice Emitted when proposal failed\n */\n event ReceivePayloadFailed(uint16 indexed srcChainId, bytes indexed srcAddress, uint64 nonce, bytes reason);\n\n /**\n * @notice Emitted when proposal is canceled\n */\n event ProposalCanceled(uint256 indexed id);\n\n /**\n * @notice Emitted when timelock added\n */\n event TimelockAdded(uint8 routeType, address indexed oldTimelock, address indexed newTimelock);\n\n /**\n * @notice Emitted when source layerzero endpoint id is updated\n */\n event SetSrcChainId(uint16 indexed oldSrcChainId, uint16 indexed newSrcChainId);\n\n /**\n * @notice Emitted when new guardian address is set\n */\n event NewGuardian(address indexed oldGuardian, address indexed newGuardian);\n\n /**\n * @notice Emitted when pending admin of Timelock is updated\n */\n event SetTimelockPendingAdmin(address, uint8);\n\n /**\n * @notice Thrown when proposal ID is invalid\n */\n error InvalidProposalId();\n\n constructor(address endpoint_, address guardian_, uint16 srcChainId_) BaseOmnichainControllerDest(endpoint_) {\n ensureNonzeroAddress(guardian_);\n guardian = guardian_;\n srcChainId = srcChainId_;\n }\n\n /**\n * @notice Update source layerzero endpoint id\n * @param srcChainId_ The new source chain id to be set\n * @custom:event Emit SetSrcChainId with old and new source id\n * @custom:access Only owner\n */\n function setSrcChainId(uint16 srcChainId_) external onlyOwner {\n emit SetSrcChainId(srcChainId, srcChainId_);\n srcChainId = srcChainId_;\n }\n\n /**\n * @notice Sets the new executor guardian\n * @param newGuardian The address of the new guardian\n * @custom:access Must be call by guardian or owner\n * @custom:event Emit NewGuardian with old and new guardian address\n */\n function setGuardian(address newGuardian) external {\n require(\n msg.sender == guardian || msg.sender == owner(),\n \"OmnichainGovernanceExecutor::setGuardian: owner or guardian only\"\n );\n ensureNonzeroAddress(newGuardian);\n emit NewGuardian(guardian, newGuardian);\n guardian = newGuardian;\n }\n\n /**\n * @notice Add timelocks to the ProposalTimelocks mapping\n * @param timelocks_ Array of addresses of all 3 timelocks\n * @custom:access Only owner\n * @custom:event Emits TimelockAdded with old and new timelock and route type\n */\n function addTimelocks(ITimelock[] memory timelocks_) external onlyOwner {\n uint8 length = uint8(type(ProposalType).max) + 1;\n require(\n timelocks_.length == length,\n \"OmnichainGovernanceExecutor::addTimelocks:number of timelocks should match the number of governance routes\"\n );\n for (uint8 i; i < length; ++i) {\n ensureNonzeroAddress(address(timelocks_[i]));\n emit TimelockAdded(i, address(proposalTimelocks[i]), address(timelocks_[i]));\n proposalTimelocks[i] = timelocks_[i];\n }\n }\n\n /**\n * @notice Executes a queued proposal if eta has passed\n * @param proposalId_ Id of proposal that is to be executed\n * @custom:event Emits ProposalExecuted with proposal id of executed proposal\n */\n function execute(uint256 proposalId_) external nonReentrant {\n require(\n state(proposalId_) == ProposalState.Queued,\n \"OmnichainGovernanceExecutor::execute: proposal can only be executed if it is queued\"\n );\n\n Proposal storage proposal = proposals[proposalId_];\n proposal.executed = true;\n ITimelock timelock = proposalTimelocks[proposal.proposalType];\n uint256 eta = proposal.eta;\n uint256 length = proposal.targets.length;\n\n emit ProposalExecuted(proposalId_);\n\n for (uint256 i; i < length; ++i) {\n timelock.executeTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n delete queued[proposalId_];\n }\n\n /**\n * @notice Cancels a proposal only if sender is the guardian and proposal is not executed\n * @param proposalId_ Id of proposal that is to be canceled\n * @custom:access Sender must be the guardian\n * @custom:event Emits ProposalCanceled with proposal id of the canceled proposal\n */\n function cancel(uint256 proposalId_) external {\n require(\n state(proposalId_) == ProposalState.Queued,\n \"OmnichainGovernanceExecutor::cancel: proposal should be queued and not executed\"\n );\n Proposal storage proposal = proposals[proposalId_];\n require(msg.sender == guardian, \"OmnichainGovernanceExecutor::cancel: sender must be guardian\");\n\n proposal.canceled = true;\n ITimelock timelock = proposalTimelocks[proposal.proposalType];\n uint256 eta = proposal.eta;\n uint256 length = proposal.targets.length;\n\n emit ProposalCanceled(proposalId_);\n\n for (uint256 i; i < length; ++i) {\n timelock.cancelTransaction(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta\n );\n }\n delete queued[proposalId_];\n }\n\n /**\n * @notice Sets the new pending admin of the Timelock\n * @param pendingAdmin_ Address of new pending admin\n * @param proposalType_ Type of proposal\n * @custom:access Only owner\n * @custom:event Emits SetTimelockPendingAdmin with new pending admin and proposal type\n */\n function setTimelockPendingAdmin(address pendingAdmin_, uint8 proposalType_) external onlyOwner {\n uint8 proposalTypeLength = uint8(type(ProposalType).max) + 1;\n require(\n proposalType_ < proposalTypeLength,\n \"OmnichainGovernanceExecutor::setTimelockPendingAdmin: invalid proposal type\"\n );\n\n proposalTimelocks[proposalType_].setPendingAdmin(pendingAdmin_);\n emit SetTimelockPendingAdmin(pendingAdmin_, proposalType_);\n }\n\n /**\n * @notice Resends a previously failed message\n * @param srcChainId_ Source chain Id\n * @param srcAddress_ Source address => local app address + remote app address\n * @param nonce_ Nonce to identify failed message\n * @param payload_ The payload of the message to be retried\n * @custom:access Only owner\n */\n function retryMessage(\n uint16 srcChainId_,\n bytes calldata srcAddress_,\n uint64 nonce_,\n bytes calldata payload_\n ) public payable override onlyOwner nonReentrant {\n require(\n keccak256(trustedRemoteLookup[srcChainId_]) == keccak256(srcAddress_),\n \"OmnichainGovernanceExecutor::retryMessage: not a trusted remote\"\n );\n super.retryMessage(srcChainId_, srcAddress_, nonce_, payload_);\n }\n\n /**\n * @notice Gets the state of a proposal\n * @param proposalId_ The id of the proposal\n * @return Proposal state\n */\n function state(uint256 proposalId_) public view returns (ProposalState) {\n Proposal storage proposal = proposals[proposalId_];\n if (proposal.canceled) {\n return ProposalState.Canceled;\n } else if (proposal.executed) {\n return ProposalState.Executed;\n } else if (queued[proposalId_]) {\n // queued only when proposal is received\n return ProposalState.Queued;\n } else {\n revert InvalidProposalId();\n }\n }\n\n /**\n * @notice Process blocking LayerZero receive request\n * @param srcChainId_ Source chain Id\n * @param srcAddress_ Source address from which payload is received\n * @param nonce_ Nonce associated with the payload to prevent replay attacks\n * @param payload_ Encoded payload containing proposal information\n * @custom:event Emit ReceivePayloadFailed if call fails\n */\n function _blockingLzReceive(\n uint16 srcChainId_,\n bytes memory srcAddress_,\n uint64 nonce_,\n bytes memory payload_\n ) internal virtual override {\n require(srcChainId_ == srcChainId, \"OmnichainGovernanceExecutor::_blockingLzReceive: invalid source chain id\");\n bytes32 hashedPayload = keccak256(payload_);\n bytes memory callData = abi.encodeCall(this.nonblockingLzReceive, (srcChainId_, srcAddress_, nonce_, payload_));\n\n (bool success, bytes memory reason) = address(this).excessivelySafeCall(gasleft() - 30000, 150, callData);\n // try-catch all errors/exceptions\n if (!success) {\n failedMessages[srcChainId_][srcAddress_][nonce_] = hashedPayload;\n emit ReceivePayloadFailed(srcChainId_, srcAddress_, nonce_, reason); // Retrieve payload from the src side tx if needed to clear\n }\n }\n\n /**\n * @notice Process non blocking LayerZero receive request\n * @param payload_ Encoded payload containing proposal information\n * @custom:event Emit ProposalReceived\n */\n function _nonblockingLzReceive(\n uint16,\n bytes memory,\n uint64,\n bytes memory payload_\n ) internal virtual override whenNotPaused {\n (bytes memory payload, uint256 pId) = abi.decode(payload_, (bytes, uint256));\n (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n uint8 pType\n ) = abi.decode(payload, (address[], uint256[], string[], bytes[], uint8));\n require(proposals[pId].id == 0, \"OmnichainGovernanceExecutor::_nonblockingLzReceive: duplicate proposal\");\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"OmnichainGovernanceExecutor::_nonblockingLzReceive: proposal function information arity mismatch\"\n );\n require(\n pType < uint8(type(ProposalType).max) + 1,\n \"OmnichainGovernanceExecutor::_nonblockingLzReceive: invalid proposal type\"\n );\n _isEligibleToReceive(targets.length);\n\n Proposal memory newProposal = Proposal({\n id: pId,\n eta: 0,\n targets: targets,\n values: values,\n signatures: signatures,\n calldatas: calldatas,\n canceled: false,\n executed: false,\n proposalType: pType\n });\n\n proposals[pId] = newProposal;\n lastProposalReceived = pId;\n\n emit ProposalReceived(newProposal.id, targets, values, signatures, calldatas, pType);\n _queue(pId);\n }\n\n /**\n * @notice Queue proposal for execution\n * @param proposalId_ Proposal to be queued\n * @custom:event Emit ProposalQueued with proposal id and eta\n */\n function _queue(uint256 proposalId_) internal {\n Proposal storage proposal = proposals[proposalId_];\n uint256 eta = block.timestamp + proposalTimelocks[proposal.proposalType].delay();\n\n proposal.eta = eta;\n queued[proposalId_] = true;\n uint8 proposalType = proposal.proposalType;\n uint256 length = proposal.targets.length;\n emit ProposalQueued(proposalId_, eta);\n\n for (uint256 i; i < length; ++i) {\n _queueOrRevertInternal(\n proposal.targets[i],\n proposal.values[i],\n proposal.signatures[i],\n proposal.calldatas[i],\n eta,\n proposalType\n );\n }\n }\n\n /**\n * @notice Check for unique proposal\n * @param target_ Address of the contract with the method to be called\n * @param value_ Native token amount sent with the transaction\n * @param signature_ Signature of the function to be called\n * @param data_ Arguments to be passed to the function when called\n * @param eta_ Timestamp after which the transaction can be executed\n * @param proposalType_ Type of proposal\n */\n function _queueOrRevertInternal(\n address target_,\n uint256 value_,\n string memory signature_,\n bytes memory data_,\n uint256 eta_,\n uint8 proposalType_\n ) internal {\n require(\n !proposalTimelocks[proposalType_].queuedTransactions(\n keccak256(abi.encode(target_, value_, signature_, data_, eta_))\n ),\n \"OmnichainGovernanceExecutor::queueOrRevertInternal: identical proposal action already queued at eta\"\n );\n\n proposalTimelocks[proposalType_].queueTransaction(target_, value_, signature_, data_, eta_);\n }\n}\n" + }, + "contracts/Cross-chain/OmnichainProposalSender.sol": { + "content": "// SPDX-License-Identifier: MIT\n\npragma solidity 0.8.25;\n\nimport { ReentrancyGuard } from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\nimport { ILayerZeroEndpoint } from \"@layerzerolabs/solidity-examples/contracts/lzApp/interfaces/ILayerZeroEndpoint.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\nimport { BaseOmnichainControllerSrc } from \"./BaseOmnichainControllerSrc.sol\";\n\n/**\n * @title OmnichainProposalSender\n * @author Venus\n * @notice OmnichainProposalSender contract builds upon the functionality of its parent contract , BaseOmnichainControllerSrc\n * It sends a proposal's data to remote chains for execution after the proposal passes on the main chain\n * when used with GovernorBravo, the owner of this contract must be set to the Timelock contract\n * @custom:security-contact https://github.com/VenusProtocol/governance-contracts#discussion\n */\n\ncontract OmnichainProposalSender is ReentrancyGuard, BaseOmnichainControllerSrc {\n /**\n * @notice Stores the total number of remote proposals\n */\n uint256 public proposalCount;\n\n /**\n * @notice Execution hashes of failed messages\n * @dev [proposalId] -> [executionHash]\n */\n mapping(uint256 => bytes32) public storedExecutionHashes;\n\n /**\n * @notice LayerZero endpoint for sending messages to remote chains\n */\n ILayerZeroEndpoint public immutable LZ_ENDPOINT;\n\n /**\n * @notice Specifies the allowed path for sending messages (remote chainId => remote app address + local app address)\n */\n mapping(uint16 => bytes) public trustedRemoteLookup;\n\n /**\n * @notice Emitted when a remote message receiver is set for the remote chain\n */\n event SetTrustedRemoteAddress(uint16 indexed remoteChainId, bytes oldRemoteAddress, bytes newRemoteAddress);\n\n /**\n * @notice Event emitted when trusted remote sets to empty\n */\n event TrustedRemoteRemoved(uint16 indexed chainId);\n\n /**\n * @notice Emitted when a proposal execution request is sent to the remote chain\n */\n event ExecuteRemoteProposal(uint16 indexed remoteChainId, uint256 proposalId, bytes payload);\n\n /**\n * @notice Emitted when a previously failed message is successfully sent to the remote chain\n */\n event ClearPayload(uint256 indexed proposalId, bytes32 executionHash);\n\n /**\n * @notice Emitted when an execution hash of a failed message is saved\n */\n event StorePayload(\n uint256 indexed proposalId,\n uint16 indexed remoteChainId,\n bytes payload,\n bytes adapterParams,\n uint256 value,\n bytes reason\n );\n /**\n * @notice Emitted while fallback withdraw\n */\n event FallbackWithdraw(address indexed receiver, uint256 value);\n\n constructor(\n ILayerZeroEndpoint lzEndpoint_,\n address accessControlManager_\n ) BaseOmnichainControllerSrc(accessControlManager_) {\n ensureNonzeroAddress(address(lzEndpoint_));\n LZ_ENDPOINT = lzEndpoint_;\n }\n\n /**\n * @notice Estimates LayerZero fees for cross-chain message delivery to the remote chain\n * @dev The estimated fees are the minimum required; it's recommended to increase the fees amount when sending a message. The unused amount will be refunded\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param payload_ The payload to be sent to the remote chain. It's computed as follows:\n * payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param useZro_ Bool that indicates whether to pay in ZRO tokens or not\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @return nativeFee The amount of fee in the native gas token (e.g. ETH)\n * @return zroFee The amount of fee in ZRO token\n */\n function estimateFees(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bool useZro_,\n bytes calldata adapterParams_\n ) external view returns (uint256, uint256) {\n return LZ_ENDPOINT.estimateFees(remoteChainId_, address(this), payload_, useZro_, adapterParams_);\n }\n\n /**\n * @notice Remove trusted remote from storage\n * @param remoteChainId_ The chain's id corresponds to setting the trusted remote to empty\n * @custom:access Controlled by Access Control Manager\n * @custom:event Emit TrustedRemoteRemoved with remote chain id\n */\n function removeTrustedRemote(uint16 remoteChainId_) external {\n _ensureAllowed(\"removeTrustedRemote(uint16)\");\n require(trustedRemoteLookup[remoteChainId_].length != 0, \"OmnichainProposalSender: trusted remote not found\");\n delete trustedRemoteLookup[remoteChainId_];\n emit TrustedRemoteRemoved(remoteChainId_);\n }\n\n /**\n * @notice Sends a message to execute a remote proposal\n * @dev Stores the hash of the execution parameters if sending fails (e.g., due to insufficient fees)\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(targets, values, signatures, calldatas, proposalType)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction. This must be either address(this) or tx.origin\n * @custom:event Emits ExecuteRemoteProposal with remote chain id, proposal ID and payload on success\n * @custom:event Emits StorePayload with last stored payload proposal ID ,remote chain id , payload, adapter params , values and reason for failure\n * @custom:access Controlled by Access Control Manager\n */\n function execute(\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_\n ) external payable whenNotPaused {\n _ensureAllowed(\"execute(uint16,bytes,bytes,address)\");\n\n // A zero value will result in a failed message; therefore, a positive value is required to send a message across the chain.\n require(msg.value > 0, \"OmnichainProposalSender: value cannot be zero\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n _validateProposal(remoteChainId_, payload_);\n uint256 _pId = ++proposalCount;\n bytes memory payload = abi.encode(payload_, _pId);\n\n try\n LZ_ENDPOINT.send{ value: msg.value }(\n remoteChainId_,\n trustedRemote,\n payload,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n )\n {\n emit ExecuteRemoteProposal(remoteChainId_, _pId, payload);\n } catch (bytes memory reason) {\n storedExecutionHashes[_pId] = keccak256(abi.encode(remoteChainId_, payload, adapterParams_, msg.value));\n emit StorePayload(_pId, remoteChainId_, payload, adapterParams_, msg.value, reason);\n }\n }\n\n /**\n * @notice Resends a previously failed message\n * @dev Allows providing more fees if needed. The extra fees will be refunded to the caller\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param zroPaymentAddress_ The address of the ZRO token holder who would pay for the transaction.\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:access Controlled by Access Control Manager\n */\n function retryExecute(\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n address zroPaymentAddress_,\n uint256 originalValue_\n ) external payable whenNotPaused nonReentrant {\n _ensureAllowed(\"retryExecute(uint256,uint16,bytes,bytes,address,uint256)\");\n bytes memory trustedRemote = trustedRemoteLookup[remoteChainId_];\n require(trustedRemote.length != 0, \"OmnichainProposalSender: destination chain is not a trusted source\");\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n (bytes memory payload, ) = abi.decode(payload_, (bytes, uint256));\n _validateProposal(remoteChainId_, payload);\n\n require(\n keccak256(abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_)) == hash,\n \"OmnichainProposalSender: invalid execution params\"\n );\n\n delete storedExecutionHashes[pId_];\n\n emit ClearPayload(pId_, hash);\n\n LZ_ENDPOINT.send{ value: originalValue_ + msg.value }(\n remoteChainId_,\n trustedRemote,\n payload_,\n payable(msg.sender),\n zroPaymentAddress_,\n adapterParams_\n );\n }\n\n /**\n * @notice Clear previously failed message\n * @param to_ Address of the receiver\n * @param pId_ The proposal ID to identify a failed message\n * @param remoteChainId_ The LayerZero id of the remote chain\n * @param payload_ The payload to be sent to the remote chain\n * It's computed as follows: payload = abi.encode(abi.encode(targets, values, signatures, calldatas, proposalType), pId)\n * @param adapterParams_ The params used to specify the custom amount of gas required for the execution on the destination\n * @param originalValue_ The msg.value passed when execute() function was called\n * @custom:access Only owner\n * @custom:event Emits ClearPayload with proposal ID and hash\n * @custom:event Emits FallbackWithdraw with receiver and amount\n */\n function fallbackWithdraw(\n address to_,\n uint256 pId_,\n uint16 remoteChainId_,\n bytes calldata payload_,\n bytes calldata adapterParams_,\n uint256 originalValue_\n ) external onlyOwner nonReentrant {\n ensureNonzeroAddress(to_);\n require(originalValue_ > 0, \"OmnichainProposalSender: invalid native amount\");\n require(payload_.length != 0, \"OmnichainProposalSender: empty payload\");\n\n bytes32 hash = storedExecutionHashes[pId_];\n require(hash != bytes32(0), \"OmnichainProposalSender: no stored payload\");\n\n bytes memory execution = abi.encode(remoteChainId_, payload_, adapterParams_, originalValue_);\n require(keccak256(execution) == hash, \"OmnichainProposalSender: invalid execution params\");\n\n delete storedExecutionHashes[pId_];\n\n emit FallbackWithdraw(to_, originalValue_);\n emit ClearPayload(pId_, hash);\n\n // Transfer the native to the `to_` address\n (bool sent, ) = to_.call{ value: originalValue_ }(\"\");\n require(sent, \"Call failed\");\n }\n\n /**\n * @notice Sets the remote message receiver address\n * @param remoteChainId_ The LayerZero id of a remote chain\n * @param newRemoteAddress_ The address of the contract on the remote chain to receive messages sent by this contract\n * @custom:access Controlled by AccessControlManager\n * @custom:event Emits SetTrustedRemoteAddress with remote chain Id and remote address\n */\n function setTrustedRemoteAddress(uint16 remoteChainId_, bytes calldata newRemoteAddress_) external {\n _ensureAllowed(\"setTrustedRemoteAddress(uint16,bytes)\");\n require(remoteChainId_ != 0, \"OmnichainProposalSender: chainId must not be zero\");\n ensureNonzeroAddress(address(uint160(bytes20(newRemoteAddress_))));\n require(newRemoteAddress_.length == 20, \"OmnichainProposalSender: remote address must be 20 bytes long\");\n bytes memory oldRemoteAddress = trustedRemoteLookup[remoteChainId_];\n trustedRemoteLookup[remoteChainId_] = abi.encodePacked(newRemoteAddress_, address(this));\n emit SetTrustedRemoteAddress(remoteChainId_, oldRemoteAddress, trustedRemoteLookup[remoteChainId_]);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId for the pending config change\n * @param configType_ The type of configuration. Every messaging library has its own convention\n * @param config_ The configuration in bytes. It can encode arbitrary content\n * @custom:access Controlled by AccessControlManager\n */\n function setConfig(uint16 version_, uint16 chainId_, uint256 configType_, bytes calldata config_) external {\n _ensureAllowed(\"setConfig(uint16,uint16,uint256,bytes)\");\n LZ_ENDPOINT.setConfig(version_, chainId_, configType_, config_);\n }\n\n /**\n * @notice Sets the configuration of the LayerZero messaging library of the specified version\n * @param version_ New messaging library version\n * @custom:access Controlled by AccessControlManager\n */\n function setSendVersion(uint16 version_) external {\n _ensureAllowed(\"setSendVersion(uint16)\");\n LZ_ENDPOINT.setSendVersion(version_);\n }\n\n /**\n * @notice Gets the configuration of the LayerZero messaging library of the specified version\n * @param version_ Messaging library version\n * @param chainId_ The LayerZero chainId\n * @param configType_ Type of configuration. Every messaging library has its own convention\n */\n function getConfig(uint16 version_, uint16 chainId_, uint256 configType_) external view returns (bytes memory) {\n return LZ_ENDPOINT.getConfig(version_, chainId_, address(this), configType_);\n }\n\n function _validateProposal(uint16 remoteChainId_, bytes memory payload_) internal {\n (\n address[] memory targets,\n uint256[] memory values,\n string[] memory signatures,\n bytes[] memory calldatas,\n\n ) = abi.decode(payload_, (address[], uint[], string[], bytes[], uint8));\n require(\n targets.length == values.length &&\n targets.length == signatures.length &&\n targets.length == calldatas.length,\n \"OmnichainProposalSender: proposal function information arity mismatch\"\n );\n _isEligibleToSend(remoteChainId_, targets.length);\n }\n}\n" + }, + "contracts/Governance/AccessControlledV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol\";\n\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlledV8\n * @author Venus\n * @notice This contract is helper between access control manager and actual contract. This contract further inherited by other contract (using solidity 0.8.13)\n * to integrate access controlled mechanism. It provides initialise methods and verifying access methods.\n */\nabstract contract AccessControlledV8 is Initializable, Ownable2StepUpgradeable {\n /// @notice Access control manager contract\n IAccessControlManagerV8 private _accessControlManager;\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[49] private __gap;\n\n /// @notice Emitted when access control manager contract address is changed\n event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);\n\n /// @notice Thrown when the action is prohibited by AccessControlManager\n error Unauthorized(address sender, address calledContract, string methodSignature);\n\n function __AccessControlled_init(address accessControlManager_) internal onlyInitializing {\n __Ownable2Step_init();\n __AccessControlled_init_unchained(accessControlManager_);\n }\n\n function __AccessControlled_init_unchained(address accessControlManager_) internal onlyInitializing {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Sets the address of AccessControlManager\n * @dev Admin function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n * @custom:event Emits NewAccessControlManager event\n * @custom:access Only Governance\n */\n function setAccessControlManager(address accessControlManager_) external onlyOwner {\n _setAccessControlManager(accessControlManager_);\n }\n\n /**\n * @notice Returns the address of the access control manager contract\n */\n function accessControlManager() external view returns (IAccessControlManagerV8) {\n return _accessControlManager;\n }\n\n /**\n * @dev Internal function to set address of AccessControlManager\n * @param accessControlManager_ The new address of the AccessControlManager\n */\n function _setAccessControlManager(address accessControlManager_) internal {\n require(address(accessControlManager_) != address(0), \"invalid acess control manager address\");\n address oldAccessControlManager = address(_accessControlManager);\n _accessControlManager = IAccessControlManagerV8(accessControlManager_);\n emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);\n }\n\n /**\n * @notice Reverts if the call is not allowed by AccessControlManager\n * @param signature Method signature\n */\n function _checkAccessAllowed(string memory signature) internal view {\n bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);\n\n if (!isAllowedToCall) {\n revert Unauthorized(msg.sender, address(this), signature);\n }\n }\n}\n" + }, + "contracts/Governance/AccessControlManager.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport \"@openzeppelin/contracts/access/AccessControl.sol\";\nimport \"./IAccessControlManagerV8.sol\";\n\n/**\n * @title AccessControlManager\n * @author Venus\n * @dev This contract is a wrapper of OpenZeppelin AccessControl extending it in a way to standartize access control within Venus Smart Contract Ecosystem.\n * @notice Access control plays a crucial role in the Venus governance model. It is used to restrict functions so that they can only be called from one\n * account or list of accounts (EOA or Contract Accounts).\n *\n * The implementation of `AccessControlManager`(https://github.com/VenusProtocol/governance-contracts/blob/main/contracts/Governance/AccessControlManager.sol)\n * inherits the [Open Zeppelin AccessControl](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/AccessControl.sol)\n * contract as a base for role management logic. There are two role types: admin and granular permissions.\n * \n * ## Granular Roles\n * \n * Granular roles are built by hashing the contract address and its function signature. For example, given contract `Foo` with function `Foo.bar()` which\n * is guarded by ACM, calling `giveRolePermission` for account B do the following:\n * \n * 1. Compute `keccak256(contractFooAddress,functionSignatureBar)`\n * 1. Add the computed role to the roles of account B\n * 1. Account B now can call `ContractFoo.bar()`\n * \n * ## Admin Roles\n * \n * Admin roles allow for an address to call a function signature on any contract guarded by the `AccessControlManager`. This is particularly useful for\n * contracts created by factories.\n * \n * For Admin roles a null address is hashed in place of the contract address (`keccak256(0x0000000000000000000000000000000000000000,functionSignatureBar)`.\n * \n * In the previous example, giving account B the admin role, account B will have permissions to call the `bar()` function on any contract that is guarded by\n * ACM, not only contract A.\n * \n * ## Protocol Integration\n * \n * All restricted functions in Venus Protocol use a hook to ACM in order to check if the caller has the right permission to call the guarded function.\n * `AccessControlledV5` and `AccessControlledV8` abstract contract makes this integration easier. They call ACM's external method\n * `isAllowedToCall(address caller, string functionSig)`. Here is an example of how `setCollateralFactor` function in `Comptroller` is integrated with ACM:\n\n```\n contract Comptroller is [...] AccessControlledV8 {\n [...]\n function setCollateralFactor(VToken vToken, uint256 newCollateralFactorMantissa, uint256 newLiquidationThresholdMantissa) external {\n _checkAccessAllowed(\"setCollateralFactor(address,uint256,uint256)\");\n [...]\n }\n }\n```\n */\ncontract AccessControlManager is AccessControl, IAccessControlManagerV8 {\n /// @notice Emitted when an account is given a permission to a certain contract function\n /// @dev If contract address is 0x000..0 this means that the account is a default admin of this function and\n /// can call any contract function with this signature\n event PermissionGranted(address account, address contractAddress, string functionSig);\n\n /// @notice Emitted when an account is revoked a permission to a certain contract function\n event PermissionRevoked(address account, address contractAddress, string functionSig);\n\n constructor() {\n // Grant the contract deployer the default admin role: it will be able\n // to grant and revoke any roles\n _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);\n }\n\n /**\n * @notice Gives a function call permission to one single account\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * @param contractAddress address of contract for which call permissions will be granted\n * @dev if contractAddress is zero address, the account can access the specified function\n * on **any** contract managed by this ACL\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @param accountToPermit account that will be given access to the contract function\n * @custom:event Emits a {RoleGranted} and {PermissionGranted} events.\n */\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n grantRole(role, accountToPermit);\n emit PermissionGranted(accountToPermit, contractAddress, functionSig);\n }\n\n /**\n * @notice Revokes an account's permission to a particular function call\n * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE\n * \t\tMay emit a {RoleRevoked} event.\n * @param contractAddress address of contract for which call permissions will be revoked\n * @param functionSig signature e.g. \"functionName(uint256,bool)\"\n * @custom:event Emits {RoleRevoked} and {PermissionRevoked} events.\n */\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) public {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n revokeRole(role, accountToRevoke);\n emit PermissionRevoked(accountToRevoke, contractAddress, functionSig);\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev Since restricted contracts using this function as a permission hook, we can get contracts address with msg.sender\n * @param account for which call permissions will be checked\n * @param functionSig restricted function signature e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n *\n */\n function isAllowedToCall(address account, string calldata functionSig) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(msg.sender, functionSig));\n\n if (hasRole(role, account)) {\n return true;\n } else {\n role = keccak256(abi.encodePacked(address(0), functionSig));\n return hasRole(role, account);\n }\n }\n\n /**\n * @notice Verifies if the given account can call a contract's guarded function\n * @dev This function is used as a view function to check permissions rather than contract hook for access restriction check.\n * @param account for which call permissions will be checked against\n * @param contractAddress address of the restricted contract\n * @param functionSig signature of the restricted function e.g. \"functionName(uint256,bool)\"\n * @return false if the user account cannot call the particular contract function\n */\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) public view returns (bool) {\n bytes32 role = keccak256(abi.encodePacked(contractAddress, functionSig));\n return hasRole(role, account);\n }\n}\n" + }, + "contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + }, + "contracts/Governance/TimelockV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title TimelockV8\n * @author Venus\n * @notice The Timelock contract using solidity V8.\n * This contract also differs from the original timelock because it has a virtual function to get minimum delays\n * and allow test deployments to override the value.\n */\ncontract TimelockV8 {\n /// @notice Required period to execute a proposal transaction\n uint256 private constant DEFAULT_GRACE_PERIOD = 14 days;\n\n /// @notice Minimum amount of time a proposal transaction must be queued\n uint256 private constant DEFAULT_MINIMUM_DELAY = 1 hours;\n\n /// @notice Maximum amount of time a proposal transaction must be queued\n uint256 private constant DEFAULT_MAXIMUM_DELAY = 30 days;\n\n /// @notice Timelock admin authorized to queue and execute transactions\n address public admin;\n\n /// @notice Account proposed as the next admin\n address public pendingAdmin;\n\n /// @notice Period for a proposal transaction to be queued\n uint256 public delay;\n\n /// @notice Mapping of queued transactions\n mapping(bytes32 => bool) public queuedTransactions;\n\n /// @notice Event emitted when a new admin is accepted\n event NewAdmin(address indexed oldAdmin, address indexed newAdmin);\n\n /// @notice Event emitted when a new admin is proposed\n event NewPendingAdmin(address indexed newPendingAdmin);\n\n /// @notice Event emitted when a new delay is proposed\n event NewDelay(uint256 indexed oldDelay, uint256 indexed newDelay);\n\n /// @notice Event emitted when a proposal transaction has been cancelled\n event CancelTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /// @notice Event emitted when a proposal transaction has been executed\n event ExecuteTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n /// @notice Event emitted when a proposal transaction has been queued\n event QueueTransaction(\n bytes32 indexed txHash,\n address indexed target,\n uint256 value,\n string signature,\n bytes data,\n uint256 eta\n );\n\n constructor(address admin_, uint256 delay_) {\n require(delay_ >= MINIMUM_DELAY(), \"Timelock::constructor: Delay must exceed minimum delay.\");\n require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n ensureNonzeroAddress(admin_);\n\n admin = admin_;\n delay = delay_;\n }\n\n fallback() external payable {}\n\n /**\n * @notice Setter for the transaction queue delay\n * @param delay_ The new delay period for the transaction queue\n * @custom:access Sender must be Timelock itself\n * @custom:event Emit NewDelay with old and new delay\n */\n function setDelay(uint256 delay_) public {\n require(msg.sender == address(this), \"Timelock::setDelay: Call must come from Timelock.\");\n require(delay_ >= MINIMUM_DELAY(), \"Timelock::setDelay: Delay must exceed minimum delay.\");\n require(delay_ <= MAXIMUM_DELAY(), \"Timelock::setDelay: Delay must not exceed maximum delay.\");\n emit NewDelay(delay, delay_);\n delay = delay_;\n }\n\n /**\n * @notice Return grace period\n * @return The duration of the grace period, specified as a uint256 value.\n */\n function GRACE_PERIOD() public view virtual returns (uint256) {\n return DEFAULT_GRACE_PERIOD;\n }\n\n /**\n * @notice Return required minimum delay\n * @return Minimum delay\n */\n function MINIMUM_DELAY() public view virtual returns (uint256) {\n return DEFAULT_MINIMUM_DELAY;\n }\n\n /**\n * @notice Return required maximum delay\n * @return Maximum delay\n */\n function MAXIMUM_DELAY() public view virtual returns (uint256) {\n return DEFAULT_MAXIMUM_DELAY;\n }\n\n /**\n * @notice Method for accepting a proposed admin\n * @custom:access Sender must be pending admin\n * @custom:event Emit NewAdmin with old and new admin\n */\n function acceptAdmin() public {\n require(msg.sender == pendingAdmin, \"Timelock::acceptAdmin: Call must come from pendingAdmin.\");\n emit NewAdmin(admin, msg.sender);\n admin = msg.sender;\n pendingAdmin = address(0);\n }\n\n /**\n * @notice Method to propose a new admin authorized to call timelock functions. This should be the Governor Contract\n * @param pendingAdmin_ Address of the proposed admin\n * @custom:access Sender must be Timelock contract itself or admin\n * @custom:event Emit NewPendingAdmin with new pending admin\n */\n function setPendingAdmin(address pendingAdmin_) public {\n require(\n msg.sender == address(this) || msg.sender == admin,\n \"Timelock::setPendingAdmin: Call must come from Timelock.\"\n );\n ensureNonzeroAddress(pendingAdmin_);\n pendingAdmin = pendingAdmin_;\n\n emit NewPendingAdmin(pendingAdmin);\n }\n\n /**\n * @notice Called for each action when queuing a proposal\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Hash of the queued transaction\n * @custom:access Sender must be admin\n * @custom:event Emit QueueTransaction\n */\n function queueTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public returns (bytes32) {\n require(msg.sender == admin, \"Timelock::queueTransaction: Call must come from admin.\");\n require(\n eta >= getBlockTimestamp() + delay,\n \"Timelock::queueTransaction: Estimated execution block must satisfy delay.\"\n );\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(!queuedTransactions[txHash], \"Timelock::queueTransaction: transaction already queued.\");\n queuedTransactions[txHash] = true;\n\n emit QueueTransaction(txHash, target, value, signature, data, eta);\n return txHash;\n }\n\n /**\n * @notice Called to cancel a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @custom:access Sender must be admin\n * @custom:event Emit CancelTransaction\n */\n function cancelTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public {\n require(msg.sender == admin, \"Timelock::cancelTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(queuedTransactions[txHash], \"Timelock::cancelTransaction: transaction is not queued yet.\");\n delete (queuedTransactions[txHash]);\n\n emit CancelTransaction(txHash, target, value, signature, data, eta);\n }\n\n /**\n * @notice Called to execute a queued transaction\n * @param target Address of the contract with the method to be called\n * @param value Native token amount sent with the transaction\n * @param signature Signature of the function to be called\n * @param data Arguments to be passed to the function when called\n * @param eta Timestamp after which the transaction can be executed\n * @return Result of function call\n * @custom:access Sender must be admin\n * @custom:event Emit ExecuteTransaction\n */\n function executeTransaction(\n address target,\n uint256 value,\n string calldata signature,\n bytes calldata data,\n uint256 eta\n ) public returns (bytes memory) {\n require(msg.sender == admin, \"Timelock::executeTransaction: Call must come from admin.\");\n\n bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));\n require(queuedTransactions[txHash], \"Timelock::executeTransaction: Transaction hasn't been queued.\");\n require(getBlockTimestamp() >= eta, \"Timelock::executeTransaction: Transaction hasn't surpassed time lock.\");\n require(getBlockTimestamp() <= eta + GRACE_PERIOD(), \"Timelock::executeTransaction: Transaction is stale.\");\n\n delete (queuedTransactions[txHash]);\n\n bytes memory callData;\n\n if (bytes(signature).length == 0) {\n callData = data;\n } else {\n callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);\n }\n\n // solium-disable-next-line security/no-call-value\n (bool success, bytes memory returnData) = target.call{ value: value }(callData);\n require(success, \"Timelock::executeTransaction: Transaction execution reverted.\");\n\n emit ExecuteTransaction(txHash, target, value, signature, data, eta);\n\n return returnData;\n }\n\n /**\n * @notice Returns the current block timestamp\n * @return The current block timestamp\n */\n function getBlockTimestamp() internal view returns (uint256) {\n // solium-disable-next-line security/no-block-members\n return block.timestamp;\n }\n}\n" + }, + "contracts/test/MockAccessTest.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport \"../Governance/AccessControlledV8.sol\";\nimport \"@layerzerolabs/solidity-examples/contracts/lzApp/mocks/LZEndpointMock.sol\";\n\ncontract MockAccessTest is AccessControlledV8 {\n /**\n * @param accessControlManager Access control manager contract address\n */\n function initialize(address accessControlManager) external initializer {\n __AccessControlled_init_unchained(accessControlManager);\n }\n}\n" + }, + "contracts/test/MockXVSVault.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\ncontract MockXVSVault {\n /* solhint-disable no-unused-vars */\n function getPriorVotes(address account, uint256 blockNumber) external view returns (uint96) {\n /* solhint-enable no-unused-vars */\n return 0;\n }\n}\n" + }, + "contracts/test/TestTimelockV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\nimport { TimelockV8 } from \"../Governance/TimelockV8.sol\";\n\ncontract TestTimelockV8 is TimelockV8 {\n constructor(address admin_, uint256 delay_) public TimelockV8(admin_, delay_) {}\n\n function GRACE_PERIOD() public view override returns (uint256) {\n return 1 hours;\n }\n\n function MINIMUM_DELAY() public view override returns (uint256) {\n return 1;\n }\n\n function MAXIMUM_DELAY() public view override returns (uint256) {\n return 1 hours;\n }\n}\n" + }, + "contracts/Utils/ACMCommandsAggregator.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport { IAccessControlManagerV8 } from \"../Governance/IAccessControlManagerV8.sol\";\nimport { ensureNonzeroAddress } from \"@venusprotocol/solidity-utilities/contracts/validators.sol\";\n\n/**\n * @title ACMCommandsAggregator\n * @author Venus\n * @notice This contract is a helper to aggregate multiple grant and revoke permissions in batches and execute them in one go.\n */\ncontract ACMCommandsAggregator {\n /*\n * @notice Struct to store permission details\n */\n struct Permission {\n /*\n * @notice Address of the contract\n */\n address contractAddress;\n /*\n * @notice Function signature\n */\n string functionSig;\n /*\n * @notice Address of the account\n */\n address account;\n }\n\n /**\n * @notice Access control manager contract\n */\n IAccessControlManagerV8 public immutable ACM;\n\n /*\n * @notice 2D array to store grant permissions in batches\n */\n Permission[][] public grantPermissions;\n\n /*\n * @notice 2D array to store revoke permissions in batches\n */\n Permission[][] public revokePermissions;\n\n /*\n * @notice Event emitted when grant permissions are added\n */\n event GrantPermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when revoke permissions are added\n */\n event RevokePermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when grant permissions are executed\n */\n event GrantPermissionsExecuted(uint256 index);\n\n /*\n * @notice Event emitted when revoke permissions are executed\n */\n event RevokePermissionsExecuted(uint256 index);\n\n /*\n * @notice Error to be thrown when permissions are empty\n */\n error EmptyPermissions();\n\n /*\n * @notice Constructor to set the access control manager\n * @param _acm Address of the access control manager\n */\n constructor(IAccessControlManagerV8 _acm) {\n ensureNonzeroAddress(address(_acm));\n ACM = _acm;\n }\n\n /*\n * @notice Function to add grant permissions\n * @param _permissions Array of permissions\n * @custom:event Emits GrantPermissionsAdded event\n */\n function addGrantPermissions(Permission[] memory _permissions) external {\n if (_permissions.length == 0) {\n revert EmptyPermissions();\n }\n\n uint256 index = grantPermissions.length;\n grantPermissions.push();\n\n for (uint256 i; i < _permissions.length; ++i) {\n grantPermissions[index].push(\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n );\n }\n\n emit GrantPermissionsAdded(index);\n }\n\n /*\n * @notice Function to add revoke permissions\n * @param _permissions Array of permissions\n * @custom:event Emits RevokePermissionsAdded event\n */\n function addRevokePermissions(Permission[] memory _permissions) external {\n if (_permissions.length == 0) {\n revert EmptyPermissions();\n }\n\n uint256 index = revokePermissions.length;\n revokePermissions.push();\n\n for (uint256 i; i < _permissions.length; ++i) {\n revokePermissions[index].push(\n Permission(_permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account)\n );\n }\n\n emit RevokePermissionsAdded(index);\n }\n\n /*\n * @notice Function to execute grant permissions\n * @param index Index of the permissions array\n * @custom:event Emits GrantPermissionsExecuted event\n */\n function executeGrantPermissions(uint256 index) external {\n uint256 length = grantPermissions[index].length;\n for (uint256 i; i < length; ++i) {\n Permission memory permission = grantPermissions[index][i];\n ACM.giveCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n }\n\n emit GrantPermissionsExecuted(index);\n }\n\n /*\n * @notice Function to execute revoke permissions\n * @param index Index of the permissions array\n * @custom:event Emits RevokePermissionsExecuted event\n */\n function executeRevokePermissions(uint256 index) external {\n uint256 length = revokePermissions[index].length;\n for (uint256 i; i < length; ++i) {\n Permission memory permission = revokePermissions[index][i];\n ACM.revokeCallPermission(permission.contractAddress, permission.functionSig, permission.account);\n }\n\n emit RevokePermissionsExecuted(index);\n }\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 10000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/sepolia/solcInputs/c5ad99afd830582b4e18b887fc15722a.json b/deployments/sepolia/solcInputs/c5ad99afd830582b4e18b887fc15722a.json new file mode 100644 index 00000000..47096b84 --- /dev/null +++ b/deployments/sepolia/solcInputs/c5ad99afd830582b4e18b887fc15722a.json @@ -0,0 +1,40 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "contracts/Governance/ACMCommandsAggregator.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport {IAccessControlManagerV8} from \"../Governance/IAccessControlManagerV8.sol\";\n\ncontract ACMCommandsAggregator {\n /*\n * @notice Enum to differentiate between giving and revoking permissions\n */\n enum PermissionType {\n GIVE,\n REVOKE\n }\n\n /*\n * @notice Struct to store permission details\n */\n struct Permission {\n /*\n * @notice Type of permission\n */ \n PermissionType permissionType;\n\n /*\n * @notice Address of the contract\n */\n address contractAddress;\n\n /*\n * @notice Function signature\n */\n string functionSig;\n\n /*\n * @notice Address of the account\n */\n address account;\n }\n\n /**\n * @notice Access control manager contract\n */\n IAccessControlManagerV8 immutable public ACM;\n\n /*\n * @notice Array to store permissions\n */\n Permission[][] public permissions;\n\n /*\n * @notice Event emitted when permissions are added\n */\n event PermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when permissions are executed\n */\n event PermissionsExecuted(uint256 index);\n\n /*\n * @notice Constructor to set the access control manager\n * @param _acm Address of the access control manager\n */\n constructor(IAccessControlManagerV8 _acm) {\n ACM = _acm;\n }\n\n /*\n * @notice Function to add permissions\n * @param _permissions Array of permissions\n */\n function addPermissions(Permission[] memory _permissions) external {\n uint256 index = _permissions.length;\n for (uint256 i = 0; i < _permissions.length; i++) {\n permissions[index].push(_permissions[i]);\n }\n\n emit PermissionsAdded(index);\n }\n\n /*\n * @notice Function to execute permissions\n * @param index Index of the permissions array\n */\n function executePermissions(uint256 index) external {\n for (uint256 i = 0; i < permissions[index].length; i++) {\n if (permissions[index][i].permissionType == PermissionType.GIVE) {\n ACM.giveCallPermission(permissions[index][i].contractAddress, permissions[index][i].functionSig, permissions[index][i].account);\n } else {\n ACM.revokeCallPermission(permissions[index][i].contractAddress, permissions[index][i].functionSig, permissions[index][i].account);\n }\n }\n\n emit PermissionsExecuted(index);\n }\n}" + }, + "contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 10000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/sepolia/solcInputs/d1b723608bc0e5c4e69b41a531154535.json b/deployments/sepolia/solcInputs/d1b723608bc0e5c4e69b41a531154535.json new file mode 100644 index 00000000..c6b442c4 --- /dev/null +++ b/deployments/sepolia/solcInputs/d1b723608bc0e5c4e69b41a531154535.json @@ -0,0 +1,40 @@ +{ + "language": "Solidity", + "sources": { + "@openzeppelin/contracts/access/IAccessControl.sol": { + "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev External interface of AccessControl declared to support ERC165 detection.\n */\ninterface IAccessControl {\n /**\n * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`\n *\n * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite\n * {RoleAdminChanged} not being emitted signaling this.\n *\n * _Available since v3.1._\n */\n event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);\n\n /**\n * @dev Emitted when `account` is granted `role`.\n *\n * `sender` is the account that originated the contract call, an admin role\n * bearer except when using {AccessControl-_setupRole}.\n */\n event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Emitted when `account` is revoked `role`.\n *\n * `sender` is the account that originated the contract call:\n * - if using `revokeRole`, it is the admin role bearer\n * - if using `renounceRole`, it is the role bearer (i.e. `account`)\n */\n event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);\n\n /**\n * @dev Returns `true` if `account` has been granted `role`.\n */\n function hasRole(bytes32 role, address account) external view returns (bool);\n\n /**\n * @dev Returns the admin role that controls `role`. See {grantRole} and\n * {revokeRole}.\n *\n * To change a role's admin, use {AccessControl-_setRoleAdmin}.\n */\n function getRoleAdmin(bytes32 role) external view returns (bytes32);\n\n /**\n * @dev Grants `role` to `account`.\n *\n * If `account` had not been already granted `role`, emits a {RoleGranted}\n * event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function grantRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from `account`.\n *\n * If `account` had been granted `role`, emits a {RoleRevoked} event.\n *\n * Requirements:\n *\n * - the caller must have ``role``'s admin role.\n */\n function revokeRole(bytes32 role, address account) external;\n\n /**\n * @dev Revokes `role` from the calling account.\n *\n * Roles are often managed via {grantRole} and {revokeRole}: this function's\n * purpose is to provide a mechanism for accounts to lose their privileges\n * if they are compromised (such as when a trusted device is misplaced).\n *\n * If the calling account had been granted `role`, emits a {RoleRevoked}\n * event.\n *\n * Requirements:\n *\n * - the caller must be `account`.\n */\n function renounceRole(bytes32 role, address account) external;\n}\n" + }, + "contracts/Governance/ACMCommandsAggregator.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity 0.8.25;\n\nimport {IAccessControlManagerV8} from \"../Governance/IAccessControlManagerV8.sol\";\n\ncontract ACMCommandsAggregator {\n /*\n * @notice Enum to differentiate between giving and revoking permissions\n */\n enum PermissionType {\n GIVE,\n REVOKE\n }\n\n /*\n * @notice Struct to store permission details\n */\n struct Permission {\n /*\n * @notice Type of permission\n */ \n PermissionType permissionType;\n\n /*\n * @notice Address of the contract\n */\n address contractAddress;\n\n /*\n * @notice Function signature\n */\n string functionSig;\n\n /*\n * @notice Address of the account\n */\n address account;\n }\n\n /**\n * @notice Access control manager contract\n */\n IAccessControlManagerV8 immutable public ACM;\n\n /*\n * @notice Mapping to store permissions\n */\n mapping (uint256 => Permission[]) public permissions;\n\n /*\n * @notice Index for the next permissions\n */\n uint256 nextIndex;\n\n /*\n * @notice Event emitted when permissions are added\n */\n event PermissionsAdded(uint256 index);\n\n /*\n * @notice Event emitted when permissions are executed\n */\n event PermissionsExecuted(uint256 index);\n\n /*\n * @notice Constructor to set the access control manager\n * @param _acm Address of the access control manager\n */\n constructor(IAccessControlManagerV8 _acm) {\n ACM = _acm;\n }\n\n /*\n * @notice Function to add permissions\n * @param _permissions Array of permissions\n */\n function addPermissions(Permission[] memory _permissions) external {\n for (uint256 i = 0; i < _permissions.length; i++) {\n permissions[nextIndex].push(Permission(_permissions[i].permissionType, _permissions[i].contractAddress, _permissions[i].functionSig, _permissions[i].account));\n }\n\n emit PermissionsAdded(nextIndex);\n nextIndex++;\n }\n\n /*\n * @notice Function to execute permissions\n * @param index Index of the permissions array\n */\n function executePermissions(uint256 index) external {\n for (uint256 i = 0; i < permissions[index].length; i++) {\n if (permissions[index][i].permissionType == PermissionType.GIVE) {\n ACM.giveCallPermission(permissions[index][i].contractAddress, permissions[index][i].functionSig, permissions[index][i].account);\n } else {\n ACM.revokeCallPermission(permissions[index][i].contractAddress, permissions[index][i].functionSig, permissions[index][i].account);\n }\n }\n\n emit PermissionsExecuted(index);\n }\n}" + }, + "contracts/Governance/IAccessControlManagerV8.sol": { + "content": "// SPDX-License-Identifier: BSD-3-Clause\npragma solidity ^0.8.25;\n\nimport \"@openzeppelin/contracts/access/IAccessControl.sol\";\n\n/**\n * @title IAccessControlManagerV8\n * @author Venus\n * @notice Interface implemented by the `AccessControlManagerV8` contract.\n */\ninterface IAccessControlManagerV8 is IAccessControl {\n function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;\n\n function revokeCallPermission(\n address contractAddress,\n string calldata functionSig,\n address accountToRevoke\n ) external;\n\n function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);\n\n function hasPermission(\n address account,\n address contractAddress,\n string calldata functionSig\n ) external view returns (bool);\n}\n" + } + }, + "settings": { + "optimizer": { + "enabled": true, + "runs": 10000 + }, + "evmVersion": "paris", + "outputSelection": { + "*": { + "*": [ + "storageLayout", + "abi", + "evm.bytecode", + "evm.deployedBytecode", + "evm.methodIdentifiers", + "metadata", + "devdoc", + "userdoc", + "evm.gasEstimates" + ], + "": ["ast"] + } + }, + "metadata": { + "useLiteralContent": true + } + } +} diff --git a/deployments/sepolia_addresses.json b/deployments/sepolia_addresses.json index 5bdb8400..d9896fe7 100644 --- a/deployments/sepolia_addresses.json +++ b/deployments/sepolia_addresses.json @@ -2,6 +2,7 @@ "name": "sepolia", "chainId": "11155111", "addresses": { + "ACMCommandsAggregator": "0x0653830c55035d678e1287b2d4550519fd263d0e", "AccessControlManager": "0xbf705C00578d43B6147ab4eaE04DBBEd1ccCdc96", "CriticalTimelock": "0xA24A7A65b8968a749841988Bd7d05F6a94329fDe", "DefaultProxyAdmin": "0x01435866babd91311b1355cf3af488cca36db68e",