From 4b7ba339a18cb9ad0115e756c61d88588f48e8dc Mon Sep 17 00:00:00 2001 From: Roberto Cantu Date: Mon, 4 Nov 2024 16:15:47 -0600 Subject: [PATCH 1/2] Update infra to deploy to Arbitrum Sepolia --- hardhat.config.js | 14 ++++++++++++-- releases/1.2.15/arbitrum/config/deploy.json | 1 + releases/1.2.15/arbitrum/output/deployed.json | 1 + .../1.2.15/arbitrumsepolia/config/deploy.json | 17 +++++++++++++++++ .../arbitrumsepolia/output/deployed.json | 18 ++++++++++++++++++ releases/1.2.15/index.yml | 9 +++++++++ releases/deployments/multisigs.json | 2 ++ releases/deployments/relayers.json | 2 ++ scripts/utils/contractHelpers.js | 4 ++++ scripts/utils/deploymentFiles.js | 2 ++ 10 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 releases/1.2.15/arbitrum/config/deploy.json create mode 100644 releases/1.2.15/arbitrum/output/deployed.json create mode 100644 releases/1.2.15/arbitrumsepolia/config/deploy.json create mode 100644 releases/1.2.15/arbitrumsepolia/output/deployed.json create mode 100644 releases/1.2.15/index.yml diff --git a/hardhat.config.js b/hardhat.config.js index 6cc8e6e4..3d21c75a 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -65,7 +65,9 @@ module.exports = { mainnet: argv.etherscan, sepolia: argv.etherscan, polygon: argv.polyscan, - basesepolia: argv.basescan + arbitrumOne: argv.arbiscan, + basesepolia: argv.basescan, + arbitrumsepolia: argv.arbiscan }, customChains: [ { @@ -75,6 +77,14 @@ module.exports = { apiURL: "https://api-sepolia.basescan.org/api", browserURL: "https://sepolia.basescan.org/" } + }, + { + network: "arbitrumsepolia", + chainId: 421614, + urls: { + apiURL: "https://api-sepolia.arbiscan.io/api", + browserURL: "https://sepolia.arbiscan.io/" + } } ] }, @@ -103,7 +113,7 @@ const accountsForNetwork = (name) => [argv[`${name}Mnemonic`] && { mnemonic: arg Object.assign( module.exports.networks, Object.fromEntries( - ['mainnet', 'ropsten', 'rinkeby', 'goerli', 'kovan', 'polygon', 'mumbai', 'amoy', 'sepolia', 'basesepolia', 'local'] + ['mainnet', 'ropsten', 'rinkeby', 'goerli', 'kovan', 'polygon', 'arbitrum', 'mumbai', 'amoy', 'sepolia', 'basesepolia', 'arbitrumsepolia', 'local'] .map((name) => [name, { url: argv[`${name}Node`], accounts: accountsForNetwork(name), gasPrice: argv[`${name}GasPrice`] || 'auto' }]) .filter(([, { url }]) => url) ), diff --git a/releases/1.2.15/arbitrum/config/deploy.json b/releases/1.2.15/arbitrum/config/deploy.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/releases/1.2.15/arbitrum/config/deploy.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/releases/1.2.15/arbitrum/output/deployed.json b/releases/1.2.15/arbitrum/output/deployed.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/releases/1.2.15/arbitrum/output/deployed.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/releases/1.2.15/arbitrumsepolia/config/deploy.json b/releases/1.2.15/arbitrumsepolia/config/deploy.json new file mode 100644 index 00000000..fa3e1874 --- /dev/null +++ b/releases/1.2.15/arbitrumsepolia/config/deploy.json @@ -0,0 +1,17 @@ +{ + "FortaBridgedArbitrum": { + "impl": { + "init-args": [ + "0x233BAc002bF01DA9FEb9DE57Ff7De5B3820C1a24", + "0x95d9a757ad9C25999ffE93f3067221F04ce1Cc79", + "0x6e244cD02BBB8a6dbd7F626f05B2ef82151Ab502" + ], + "opts": { + "unsafe-allow": [ + "delegatecall" + ], + "constructor-args": [] + } + } + } +} \ No newline at end of file diff --git a/releases/1.2.15/arbitrumsepolia/output/deployed.json b/releases/1.2.15/arbitrumsepolia/output/deployed.json new file mode 100644 index 00000000..8db0f2bd --- /dev/null +++ b/releases/1.2.15/arbitrumsepolia/output/deployed.json @@ -0,0 +1,18 @@ +{ + "forta-bridged-arbitrum-deploy-tx": "0xbfd0cb53f6ae0d50834da210d5803b21ec2fad53f7685527a575ea137691e09e", + "forta-bridged-arbitrum": { + "address": "0x2441Ce5eB269505f30F6F434D21E039438aaC342", + "impl": { + "address": "0x95d9a757ad9C25999ffE93f3067221F04ce1Cc79", + "constructor-args": [], + "init-args": [ + "0x233BAc002bF01DA9FEb9DE57Ff7De5B3820C1a24", + "0x95d9a757ad9C25999ffE93f3067221F04ce1Cc79", + "0x6e244cD02BBB8a6dbd7F626f05B2ef82151Ab502" + ], + "name": "FortaBridgedArbitrum", + "timeout": 1200000, + "version": "0.1.0" + } + } +} \ No newline at end of file diff --git a/releases/1.2.15/index.yml b/releases/1.2.15/index.yml new file mode 100644 index 00000000..5da55a0f --- /dev/null +++ b/releases/1.2.15/index.yml @@ -0,0 +1,9 @@ +title: FORT Arbitrum deployment +network: arbitrumsepolia +# network: arbitrum (for mainnet) +deploy: deploy-and-prepare-upgrade 1.2.15 +verify: verify-deployed +finish: propose-admin +description: | + ## Deployed new implementations on Arbitrum testnet: + - FORT token \ No newline at end of file diff --git a/releases/deployments/multisigs.json b/releases/deployments/multisigs.json index 500ec3b6..db3e5c28 100644 --- a/releases/deployments/multisigs.json +++ b/releases/deployments/multisigs.json @@ -1,7 +1,9 @@ { "mumbai": "0x19AD705930B6695812c921f08b16F7DfAF59A536", "polygon": "0x30ceaeC1d8Ed347B91d45077721c309242db3D6d", + "arbitrum": "0x0000000000000000000000000000000000000000", "sepolia": "0x0000000000000000000000000000000000000000", "basesepolia": "0x4e22284F3aDC3c023c9D8bb4Fbb27fbb96ef6d5e", + "arbitrumsepolia": "0x0000000000000000000000000000000000000000", "local": "0x233BAc002bF01DA9FEb9DE57Ff7De5B3820C1a24" } \ No newline at end of file diff --git a/releases/deployments/relayers.json b/releases/deployments/relayers.json index 9d593268..f5a04998 100644 --- a/releases/deployments/relayers.json +++ b/releases/deployments/relayers.json @@ -2,6 +2,8 @@ "mumbai": "0x2832d78949b9963f44ba2a3f15ac1ac56eeb2676", "sepolia": "0x0000000000000000000000000000000000000000", "basesepolia": "0xa17AdDd061ba541823832A983E78490CE2787e95", + "arbitrumsepolia": "0x0000000000000000000000000000000000000000", "polygon": "0x15d3c7e811582be09bb8673cd603bb2f22d1e47b", + "arbitrum": "0x0000000000000000000000000000000000000000", "local": "0x233BAc002bF01DA9FEb9DE57Ff7De5B3820C1a24" } \ No newline at end of file diff --git a/scripts/utils/contractHelpers.js b/scripts/utils/contractHelpers.js index 4bd5e43c..d2b0d4d6 100644 --- a/scripts/utils/contractHelpers.js +++ b/scripts/utils/contractHelpers.js @@ -144,6 +144,8 @@ const getBlockExplorerDomain = (hre) => { case 'polygon': case 'matic': return 'polygonscan.com'; + case 'arbitrum': + return 'arbiscan.io'; case 'mumbai': return 'mumbai.polygonscan.com'; case 'amoy': @@ -152,6 +154,8 @@ const getBlockExplorerDomain = (hre) => { return 'sepolia.etherscan.io'; case 'basesepolia': return 'sepolia.basescan.org' + case 'arbitrumsepolia': + return 'sepolia.arbiscan.io'; } }; diff --git a/scripts/utils/deploymentFiles.js b/scripts/utils/deploymentFiles.js index f0e48e86..142720db 100644 --- a/scripts/utils/deploymentFiles.js +++ b/scripts/utils/deploymentFiles.js @@ -37,10 +37,12 @@ const CHAIN_NAME = { 1: 'mainnet', 5: 'goerli', 137: 'polygon', + 42161: 'arbitrum', 80001: 'mumbai', 80002: 'amoy', 84532: 'basesepolia', 31337: 'local', + 421614: 'arbitrumsepolia', 11155111: 'sepolia' }; From 903c010fe9e7037ae417c2da005a13d51653351a Mon Sep 17 00:00:00 2001 From: Roberto Cantu Date: Mon, 4 Nov 2024 16:22:46 -0600 Subject: [PATCH 2/2] Initial FORT on Arbitrum implementation and deployments --- .openzeppelin/unknown-421614.json | 746 +++++++++++++++++++++++ contracts/token/FortaBridgedArbitrum.sol | 94 +++ contracts/token/IArbToken.sol | 44 ++ releases/deployments/42161.json | 1 + releases/deployments/421614.json | 18 + 5 files changed, 903 insertions(+) create mode 100644 .openzeppelin/unknown-421614.json create mode 100644 contracts/token/FortaBridgedArbitrum.sol create mode 100644 contracts/token/IArbToken.sol create mode 100644 releases/deployments/42161.json create mode 100644 releases/deployments/421614.json diff --git a/.openzeppelin/unknown-421614.json b/.openzeppelin/unknown-421614.json new file mode 100644 index 00000000..e2ce7409 --- /dev/null +++ b/.openzeppelin/unknown-421614.json @@ -0,0 +1,746 @@ +{ + "manifestVersion": "3.2", + "proxies": [ + { + "address": "0x2441Ce5eB269505f30F6F434D21E039438aaC342", + "txHash": "0xbfd0cb53f6ae0d50834da210d5803b21ec2fad53f7685527a575ea137691e09e", + "kind": "uups" + } + ], + "impls": { + "ba5452f42c3a4a4a469e2ef0aa7712fef3e1142a1bce8b2b8f281c70879d759a": { + "address": "0x6A434647A4a3De2F915Bb49B6227444EBbE67Aed", + "txHash": "0x5e764e9860cbccf648ede1ec1000fcbda026ea51bba3882145f6089ca45d4636", + "layout": { + "solcVersion": "0.8.9", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC165Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "label": "_roles", + "offset": 0, + "slot": "101", + "type": "t_mapping(t_bytes32,t_struct(RoleData)5114_storage)", + "contract": "AccessControlUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage", + "contract": "AccessControlUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "label": "_balances", + "offset": 0, + "slot": "151", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:37" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "152", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:39" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "153", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:41" + }, + { + "label": "_name", + "offset": 0, + "slot": "154", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:43" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "155", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "156", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:394" + }, + { + "label": "_HASHED_NAME", + "offset": 0, + "slot": "201", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:32" + }, + { + "label": "_HASHED_VERSION", + "offset": 0, + "slot": "202", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:33" + }, + { + "label": "__gap", + "offset": 0, + "slot": "203", + "type": "t_array(t_uint256)50_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:120" + }, + { + "label": "_nonces", + "offset": 0, + "slot": "253", + "type": "t_mapping(t_address,t_struct(Counter)11323_storage)", + "contract": "ERC20PermitUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol:28" + }, + { + "label": "_PERMIT_TYPEHASH_DEPRECATED_SLOT", + "offset": 0, + "slot": "254", + "type": "t_bytes32", + "contract": "ERC20PermitUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol:40", + "renamedFrom": "_PERMIT_TYPEHASH" + }, + { + "label": "__gap", + "offset": 0, + "slot": "255", + "type": "t_array(t_uint256)49_storage", + "contract": "ERC20PermitUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol:108" + }, + { + "label": "_delegates", + "offset": 0, + "slot": "304", + "type": "t_mapping(t_address,t_address)", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:42" + }, + { + "label": "_checkpoints", + "offset": 0, + "slot": "305", + "type": "t_mapping(t_address,t_array(t_struct(Checkpoint)8713_storage)dyn_storage)", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:43" + }, + { + "label": "_totalSupplyCheckpoints", + "offset": 0, + "slot": "306", + "type": "t_array(t_struct(Checkpoint)8713_storage)dyn_storage", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "307", + "type": "t_array(t_uint256)47_storage", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:261" + }, + { + "label": "__gap", + "offset": 0, + "slot": "354", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:211" + }, + { + "label": "__gap", + "offset": 0, + "slot": "404", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:107" + }, + { + "label": "deprecated_whitelistDisabled", + "offset": 0, + "slot": "454", + "type": "t_bool", + "contract": "FortaCommon", + "src": "contracts/token/FortaCommon.sol:27", + "renamedFrom": "whitelistDisabled" + }, + { + "label": "__gap", + "offset": 0, + "slot": "455", + "type": "t_array(t_uint256)49_storage", + "contract": "FortaCommon", + "src": "contracts/token/FortaCommon.sol:66" + }, + { + "label": "__gap", + "offset": 0, + "slot": "504", + "type": "t_array(t_uint256)50_storage", + "contract": "Forta", + "src": "contracts/token/Forta.sol:46" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)8713_storage)dyn_storage": { + "label": "struct ERC20VotesUpgradeable.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)47_storage": { + "label": "uint256[47]", + "numberOfBytes": "1504" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_address)": { + "label": "mapping(address => address)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_array(t_struct(Checkpoint)8713_storage)dyn_storage)": { + "label": "mapping(address => struct ERC20VotesUpgradeable.Checkpoint[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Counter)11323_storage)": { + "label": "mapping(address => struct CountersUpgradeable.Counter)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(RoleData)5114_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)8713_storage": { + "label": "struct ERC20VotesUpgradeable.Checkpoint", + "members": [ + { + "label": "fromBlock", + "type": "t_uint32", + "offset": 0, + "slot": "0" + }, + { + "label": "votes", + "type": "t_uint224", + "offset": 4, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Counter)11323_storage": { + "label": "struct CountersUpgradeable.Counter", + "members": [ + { + "label": "_value", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(RoleData)5114_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)", + "offset": 0, + "slot": "0" + }, + { + "label": "adminRole", + "type": "t_bytes32", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint224": { + "label": "uint224", + "numberOfBytes": "28" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": {} + } + }, + "487d694ffcee62eb20037ce031f6ce8674e39e43c6390871c5deef79e307026e": { + "address": "0x95d9a757ad9C25999ffE93f3067221F04ce1Cc79", + "txHash": "0x463e3169a09981e3458307bd876560489ce5fa03e818ac986e1c976883c2c92f", + "layout": { + "solcVersion": "0.8.9", + "storage": [ + { + "label": "_initialized", + "offset": 0, + "slot": "0", + "type": "t_uint8", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:62", + "retypedFrom": "bool" + }, + { + "label": "_initializing", + "offset": 1, + "slot": "0", + "type": "t_bool", + "contract": "Initializable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol:67" + }, + { + "label": "__gap", + "offset": 0, + "slot": "1", + "type": "t_array(t_uint256)50_storage", + "contract": "ContextUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol:36" + }, + { + "label": "__gap", + "offset": 0, + "slot": "51", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC165Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol:41" + }, + { + "label": "_roles", + "offset": 0, + "slot": "101", + "type": "t_mapping(t_bytes32,t_struct(RoleData)171_storage)", + "contract": "AccessControlUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:61" + }, + { + "label": "__gap", + "offset": 0, + "slot": "102", + "type": "t_array(t_uint256)49_storage", + "contract": "AccessControlUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol:259" + }, + { + "label": "_balances", + "offset": 0, + "slot": "151", + "type": "t_mapping(t_address,t_uint256)", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:37" + }, + { + "label": "_allowances", + "offset": 0, + "slot": "152", + "type": "t_mapping(t_address,t_mapping(t_address,t_uint256))", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:39" + }, + { + "label": "_totalSupply", + "offset": 0, + "slot": "153", + "type": "t_uint256", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:41" + }, + { + "label": "_name", + "offset": 0, + "slot": "154", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:43" + }, + { + "label": "_symbol", + "offset": 0, + "slot": "155", + "type": "t_string_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "156", + "type": "t_array(t_uint256)45_storage", + "contract": "ERC20Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol:394" + }, + { + "label": "_HASHED_NAME", + "offset": 0, + "slot": "201", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:32" + }, + { + "label": "_HASHED_VERSION", + "offset": 0, + "slot": "202", + "type": "t_bytes32", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:33" + }, + { + "label": "__gap", + "offset": 0, + "slot": "203", + "type": "t_array(t_uint256)50_storage", + "contract": "EIP712Upgradeable", + "src": "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol:120" + }, + { + "label": "_nonces", + "offset": 0, + "slot": "253", + "type": "t_mapping(t_address,t_struct(Counter)3192_storage)", + "contract": "ERC20PermitUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol:28" + }, + { + "label": "_PERMIT_TYPEHASH_DEPRECATED_SLOT", + "offset": 0, + "slot": "254", + "type": "t_bytes32", + "contract": "ERC20PermitUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol:40", + "renamedFrom": "_PERMIT_TYPEHASH" + }, + { + "label": "__gap", + "offset": 0, + "slot": "255", + "type": "t_array(t_uint256)49_storage", + "contract": "ERC20PermitUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol:108" + }, + { + "label": "_delegates", + "offset": 0, + "slot": "304", + "type": "t_mapping(t_address,t_address)", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:42" + }, + { + "label": "_checkpoints", + "offset": 0, + "slot": "305", + "type": "t_mapping(t_address,t_array(t_struct(Checkpoint)2024_storage)dyn_storage)", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:43" + }, + { + "label": "_totalSupplyCheckpoints", + "offset": 0, + "slot": "306", + "type": "t_array(t_struct(Checkpoint)2024_storage)dyn_storage", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:44" + }, + { + "label": "__gap", + "offset": 0, + "slot": "307", + "type": "t_array(t_uint256)47_storage", + "contract": "ERC20VotesUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol:261" + }, + { + "label": "__gap", + "offset": 0, + "slot": "354", + "type": "t_array(t_uint256)50_storage", + "contract": "ERC1967UpgradeUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol:211" + }, + { + "label": "__gap", + "offset": 0, + "slot": "404", + "type": "t_array(t_uint256)50_storage", + "contract": "UUPSUpgradeable", + "src": "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol:107" + }, + { + "label": "deprecated_whitelistDisabled", + "offset": 0, + "slot": "454", + "type": "t_bool", + "contract": "FortaCommon", + "src": "contracts/token/FortaCommon.sol:27", + "renamedFrom": "whitelistDisabled" + }, + { + "label": "__gap", + "offset": 0, + "slot": "455", + "type": "t_array(t_uint256)49_storage", + "contract": "FortaCommon", + "src": "contracts/token/FortaCommon.sol:66" + }, + { + "label": "l1TokenAddress", + "offset": 0, + "slot": "504", + "type": "t_address", + "contract": "FortaBridgedArbitrum", + "src": "contracts/token/FortaBridgedArbitrum.sol:21" + }, + { + "label": "l2ERC20Gateway", + "offset": 0, + "slot": "505", + "type": "t_address", + "contract": "FortaBridgedArbitrum", + "src": "contracts/token/FortaBridgedArbitrum.sol:22" + }, + { + "label": "__gap", + "offset": 0, + "slot": "506", + "type": "t_array(t_uint256)47_storage", + "contract": "FortaBridgedArbitrum", + "src": "contracts/token/FortaBridgedArbitrum.sol:93" + } + ], + "types": { + "t_address": { + "label": "address", + "numberOfBytes": "20" + }, + "t_array(t_struct(Checkpoint)2024_storage)dyn_storage": { + "label": "struct ERC20VotesUpgradeable.Checkpoint[]", + "numberOfBytes": "32" + }, + "t_array(t_uint256)45_storage": { + "label": "uint256[45]", + "numberOfBytes": "1440" + }, + "t_array(t_uint256)47_storage": { + "label": "uint256[47]", + "numberOfBytes": "1504" + }, + "t_array(t_uint256)49_storage": { + "label": "uint256[49]", + "numberOfBytes": "1568" + }, + "t_array(t_uint256)50_storage": { + "label": "uint256[50]", + "numberOfBytes": "1600" + }, + "t_bool": { + "label": "bool", + "numberOfBytes": "1" + }, + "t_bytes32": { + "label": "bytes32", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_address)": { + "label": "mapping(address => address)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_array(t_struct(Checkpoint)2024_storage)dyn_storage)": { + "label": "mapping(address => struct ERC20VotesUpgradeable.Checkpoint[])", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_bool)": { + "label": "mapping(address => bool)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_mapping(t_address,t_uint256))": { + "label": "mapping(address => mapping(address => uint256))", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_struct(Counter)3192_storage)": { + "label": "mapping(address => struct CountersUpgradeable.Counter)", + "numberOfBytes": "32" + }, + "t_mapping(t_address,t_uint256)": { + "label": "mapping(address => uint256)", + "numberOfBytes": "32" + }, + "t_mapping(t_bytes32,t_struct(RoleData)171_storage)": { + "label": "mapping(bytes32 => struct AccessControlUpgradeable.RoleData)", + "numberOfBytes": "32" + }, + "t_string_storage": { + "label": "string", + "numberOfBytes": "32" + }, + "t_struct(Checkpoint)2024_storage": { + "label": "struct ERC20VotesUpgradeable.Checkpoint", + "members": [ + { + "label": "fromBlock", + "type": "t_uint32", + "offset": 0, + "slot": "0" + }, + { + "label": "votes", + "type": "t_uint224", + "offset": 4, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(Counter)3192_storage": { + "label": "struct CountersUpgradeable.Counter", + "members": [ + { + "label": "_value", + "type": "t_uint256", + "offset": 0, + "slot": "0" + } + ], + "numberOfBytes": "32" + }, + "t_struct(RoleData)171_storage": { + "label": "struct AccessControlUpgradeable.RoleData", + "members": [ + { + "label": "members", + "type": "t_mapping(t_address,t_bool)", + "offset": 0, + "slot": "0" + }, + { + "label": "adminRole", + "type": "t_bytes32", + "offset": 0, + "slot": "1" + } + ], + "numberOfBytes": "64" + }, + "t_uint224": { + "label": "uint224", + "numberOfBytes": "28" + }, + "t_uint256": { + "label": "uint256", + "numberOfBytes": "32" + }, + "t_uint32": { + "label": "uint32", + "numberOfBytes": "4" + }, + "t_uint8": { + "label": "uint8", + "numberOfBytes": "1" + } + }, + "namespaces": {} + } + } + } +} diff --git a/contracts/token/FortaBridgedArbitrum.sol b/contracts/token/FortaBridgedArbitrum.sol new file mode 100644 index 00000000..40404033 --- /dev/null +++ b/contracts/token/FortaBridgedArbitrum.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: UNLICENSED +// See Forta Network License: https://github.com/forta-network/forta-contracts/blob/master/LICENSE.md + +pragma solidity ^0.8.9; + +import "./FortaCommon.sol"; +import "./IArbToken.sol"; + +/** + * This version of the Forta token is living on the Arbitrum Layer 2. + * + * On Arbitrum, when tokens are bridged from the L1, the `L2ERC20Gateway` will call the + * {bridgeMint} function, which will mint corresponding tokens on the L2 side. The total supply + * on the L2 is expected to match the amount of locked tokens on the L1. + * + * In order to bridge tokens back from the L2 to L1, any user + * can call the {outBoundTransfer} function on the `L2GatewayRouter`. This will burn tokens here, + * emitting a burn event (Transfer event from the user to address(0)) in the process. + */ +contract FortaBridgedArbitrum is FortaCommon, IArbToken { + address private l1TokenAddress; + address private l2ERC20Gateway; + + error MintOnlyByL2ERC20Gateway(); + error BurnOnlyByL2ERC20Gateway(); + + /** + * @notice Initializer method, access point to initialize inheritance tree. + * @param __admin address that will be ADMIN_ROLE. + * @param __l1TokenAddress address of L1 FORT token. + * @param __l2ERC20Gateway address of Arbitrum ERC20Gateway. + */ + function initialize(address __admin, address __l1TokenAddress, address __l2ERC20Gateway) public initializer { + if (__l1TokenAddress == address(0)) revert ZeroAddress("l1TokenAddress"); + if (__l2ERC20Gateway == address(0)) revert ZeroAddress("l2ERC20Gateway"); + + __FortaCommon_init(__admin); + l1TokenAddress = __l1TokenAddress; + l2ERC20Gateway = __l2ERC20Gateway; + } + + /** + * @notice Allows the L2ERC20Gateway on this network to mint tokens, + * as part of bridging form L1. + * @dev Only callable by L2ERC20Gateway + * @param account Address to bridge tokens to. + * @param amount Amount of tokens to bridge. + */ + function bridgeMint(address account, uint256 amount) external { + if (msg.sender != l2ERC20Gateway) revert MintOnlyByL2ERC20Gateway(); + + _mint(account, amount); + } + + /** + * @notice Allows the L2ERC20Gateway on this network to burn tokens, + * as part of bridging to L1. + * @dev Only callable by L2ERC20Gateway + * @param account Address to bridge tokens from. + * @param amount Amount of tokens to bridge. + */ + function bridgeBurn(address account, uint256 amount) external { + if (msg.sender != l2ERC20Gateway) revert BurnOnlyByL2ERC20Gateway(); + + _burn(account, amount); + } + + /** + * @notice L1 token address getter + * @return Address of layer 1 token + */ + function l1Address() external view returns (address) { + return l1TokenAddress; + } + + /** + * @notice Contract version + * @dev Since FortaCommon is IVersioned, Forta is deployed in L1 and FortaBridgedPolygon and FortaBridgedArbitrum in L2, + * we need to implement the interface with a method instead of immutable variable. + * @return version of FORT deployed in Arbitrum L2 + */ + function version() external pure returns(string memory) { + return "0.1.0"; + } + + /** + * 49 + * - 1 l1TokenAddress + * - 1 l2ERC20Gateway + * -------------------------- + * 47 __gap + */ + uint256[47] private __gap; +} diff --git a/contracts/token/IArbToken.sol b/contracts/token/IArbToken.sol new file mode 100644 index 00000000..07bef63b --- /dev/null +++ b/contracts/token/IArbToken.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: Apache-2.0 + +/* + * Copyright 2020, Offchain Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @title Minimum expected interface for L2 token that interacts with the L2 token bridge (this is the interface necessary + * for a custom token that interacts with the bridge, see TestArbCustomToken.sol for an example implementation). + * @dev For the token to be compatible out of the box with the tooling available (e.g., the Arbitrum bridge), it is + * recommended to keep the implementation of this interface as close as possible to the `TestArbCustomToken` example. + */ + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +interface IArbToken { + /** + * @notice should increase token supply by amount, and should (probably) only be callable by the L1 bridge. + */ + function bridgeMint(address account, uint256 amount) external; + + /** + * @notice should decrease token supply by amount, and should (probably) only be callable by the L1 bridge. + */ + function bridgeBurn(address account, uint256 amount) external; + + /** + * @return address of layer 1 token + */ + function l1Address() external view returns (address); +} \ No newline at end of file diff --git a/releases/deployments/42161.json b/releases/deployments/42161.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/releases/deployments/42161.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/releases/deployments/421614.json b/releases/deployments/421614.json new file mode 100644 index 00000000..cd77d084 --- /dev/null +++ b/releases/deployments/421614.json @@ -0,0 +1,18 @@ +{ + "forta-bridged-arbitrum": { + "address": "0x2441Ce5eB269505f30F6F434D21E039438aaC342", + "impl": { + "address": "0x95d9a757ad9C25999ffE93f3067221F04ce1Cc79", + "constructor-args": [], + "init-args": [ + "0x233BAc002bF01DA9FEb9DE57Ff7De5B3820C1a24", + "0x95d9a757ad9C25999ffE93f3067221F04ce1Cc79", + "0x6e244cD02BBB8a6dbd7F626f05B2ef82151Ab502" + ], + "name": "FortaBridgedArbitrum", + "timeout": 1200000, + "version": "0.1.0" + } + }, + "forta-bridged-arbitrum-deploy-tx": "0xbfd0cb53f6ae0d50834da210d5803b21ec2fad53f7685527a575ea137691e09e" +} \ No newline at end of file