diff --git a/README.md b/README.md index fab9d42..fe47f97 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,15 @@ The bridges have the same address across all supported chains. The address is `0 | Ethereum | 1 | `0x74D1984A64F447371Be4019920180b52A33aDAdD` | _True_ | | BSC | 56 | `0xB2B446386633C6746B0a2735FB57edBb066c5878` | _False_ | +--- + +`inwstETHs` + +| Chain Name | ChainId | Address | Source Chain | +| ---------- | ------- | -------------------------------------------- | ------------ | +| Ethereum | 1 | `0x8E0789d39db454DBE9f4a77aCEF6dc7c69f6D552` | _True_ | +| Zircuit | 48900 | `0x9eFdE41A87fa4dD47BAa584954e8Abd5b8bdBfE7` | _False_ | + #### Rate Providers | Asset | Chain Name | ChainId | Address | diff --git a/hardhat.config.js b/hardhat.config.js index 6bc542a..5f7b9ac 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -10,6 +10,7 @@ require("@openzeppelin/hardhat-upgrades"); require("./tasks/setup-bridge"); require("./tasks/deploy-xerc20"); +require("./tasks/deploy-xerc20-i"); require("./tasks/deploy-rate-provider"); /** @type import('hardhat/config').HardhatUserConfig */ @@ -25,108 +26,12 @@ module.exports = { chainId: 1, gas: 8000000, }, - holesky: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_HOLESKY}`, - chainId: 17000, + zircuit: { + accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`, `0x${process.env.DEPLOYER_PRIVATE_KEY_FACTORY}`], + url: `${process.env.RPC_URL_ZIRCUIT}`, + chainId: 48900, gas: 8000000, - }, - arbitrum: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_ARBITRUM}`, - chainId: 42161, - gas: 8000000, - }, - arbitrum_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_ARBITRUM_TESTNET}`, - chainId: 421614, - gas: 8000000, - }, - mode: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_MODE}`, - chainId: 34443, - gas: 8000000, - }, - mode_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_MODE_TESTNET}`, - chainId: 919, - gas: 8000000, - }, - xlayer: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_XLAYER}`, - chainId: 196, - gas: 8000000, - }, - xlayer_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_XLAYER_TESTNET}`, - chainId: 195, - gas: 8000000, - }, - linea: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_LINEA}`, - chainId: 59144, - gas: 8000000, - }, - linea_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_LINEA_TESTNET}`, - chainId: 59141, - gas: 8000000, - }, - blast: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_BLAST}`, - chainId: 81457, - gas: 8000000, - }, - blast_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_BLAST_TESTNET}`, - chainId: 168587773, - gas: 8000000, - }, - bsc: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_BSC}`, - chainId: 56, - gas: 8000000, - }, - bsc_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_BSC_TESTNET}`, - chainId: 97, - gas: 8000000, - }, - optimism: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_OPTIMISM}`, - chainId: 10, - gas: 8000000, - }, - optimism_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_OPTIMISM_TESTNET}`, - chainId: 11155420, - gas: 8000000, - }, - base: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`], - url: `${process.env.RPC_URL_BASE}`, - chainId: 8453, - gas: 8000000, - }, - base_testnet: { - accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY_TESTNET}`], - url: `${process.env.RPC_URL_BASE_TESTNET}`, - chainId: 84532, - gas: 8000000, - }, + } }, solidity: { compilers: [ diff --git a/scripts/migration/deploy-bridge.js b/scripts/migration/deploy-bridge.js index c61d2ab..db1d588 100644 --- a/scripts/migration/deploy-bridge.js +++ b/scripts/migration/deploy-bridge.js @@ -47,9 +47,9 @@ async function deployBridge(implementationAddress, factoryAddress, notaryAddress const factory = await ethers.getContractAt("BridgeFactory", factoryAddress); /// Deploy ProxyAdmin - const proxyAdmin = await ethers.deployContract("ProxyAdmin"); - await proxyAdmin.waitForDeployment(); - const proxyAdminAddress = await proxyAdmin.getAddress(); + // const proxyAdmin = await ethers.deployContract("ProxyAdmin"); + // await proxyAdmin.waitForDeployment(); + const proxyAdminAddress = "0xB81e55e7Ee6B286aF6abFEa4eFad83f7BA4D1f1e"; console.log(`ProxyAdmin address: ${proxyAdminAddress}`); /// Deploy TransparentUpgradeableProxy @@ -91,7 +91,7 @@ async function main() { console.error("factory address is null"); } - const bridgeImplAddress = await deployBridgeImpl(); + const bridgeImplAddress = "0xB2F44773e99cfFeCb00AE9ba62913EA14C3B6163"; const bridgeProxyAddress = await deployBridge(bridgeImplAddress, factoryAddress, notaryAddress); // Save the Bridge Impl address diff --git a/scripts/migration/deploy-factory.js b/scripts/migration/deploy-factory.js index 0c4f31c..2572df2 100644 --- a/scripts/migration/deploy-factory.js +++ b/scripts/migration/deploy-factory.js @@ -10,7 +10,7 @@ const deployFactory = async () => { console.log("###################### Factory deployment #######################"); console.log("##################################################################\n"); - const [deployer] = await ethers.getSigners(); + const [normalDeployer, deployer] = await ethers.getSigners(); await printBalance(deployer); if ((await deployer.getNonce()).toString() != DEPLOYER_NONCE) { @@ -22,7 +22,8 @@ const deployFactory = async () => { return; } - const factory = await ethers.deployContract("BridgeFactory"); + const Factory = await ethers.getContractFactory("BridgeFactory"); + const factory = await Factory.connect(deployer).deploy(); await factory.waitForDeployment(); const factoryAddress = await factory.getAddress(); @@ -46,5 +47,4 @@ main() .catch((error) => { console.error(error); process.exit(1); - }); - \ No newline at end of file + }); \ No newline at end of file diff --git a/scripts/migration/ownerships_e.js b/scripts/migration/ownerships_e.js new file mode 100644 index 0000000..40abaad --- /dev/null +++ b/scripts/migration/ownerships_e.js @@ -0,0 +1,34 @@ +const fs = require("fs"); +const { ethers } = require("hardhat"); +const { printBalance } = require("../utils"); + +const deployFactory = async () => { + console.log("##################################################################"); + console.log("###################### Transfering Ownerhips #####################"); + console.log("##################################################################\n"); + + const [deployer] = await ethers.getSigners(); + await printBalance(deployer); + + if (hre.network.name == "ethereum") { + + console.log("ethereum"); + + let tx; + let xerc20 = await ethers.getContractAt("XERC20", "0x9eFdE41A87fa4dD47BAa584954e8Abd5b8bdBfE7"); + + tx = await xerc20.transferOwnership("0x8e6C8799B542E507bfDDCA1a424867e885D96e79"); await tx.wait(); console.log("1"); + + } else throw ("Incorrect Network"); +}; + +async function main() { + await deployFactory(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); \ No newline at end of file diff --git a/scripts/migration/ownerships_z.js b/scripts/migration/ownerships_z.js new file mode 100644 index 0000000..6e78ebc --- /dev/null +++ b/scripts/migration/ownerships_z.js @@ -0,0 +1,41 @@ +const fs = require("fs"); +const { ethers } = require("hardhat"); +const { printBalance } = require("../utils"); + +const deployFactory = async () => { + console.log("##################################################################"); + console.log("###################### Transfering Ownerhips #####################"); + console.log("##################################################################\n"); + + const [deployer] = await ethers.getSigners(); + await printBalance(deployer); + let multisig = "0x76668e48f6D6b304Cf17a970C474942115AAAEB6"; + + if (hre.network.name == "zircuit") { + + console.log("zircuit"); + + let tx; + let pa1 = await ethers.getContractAt("InceptionBridge", "0xB81e55e7Ee6B286aF6abFEa4eFad83f7BA4D1f1e"); + let pa2 = await ethers.getContractAt("InceptionBridge", "0x67f199841416388eeAd3bc48178c36651579FA3A"); + let b = await ethers.getContractAt("InceptionBridge", "0xC00cD5599F7E128FC5Ed5563147a45B12e83B3ac"); + let x = await ethers.getContractAt("InceptionBridge", "0x9eFdE41A87fa4dD47BAa584954e8Abd5b8bdBfE7"); + + tx = await pa1.transferOwnership(multisig); await tx.wait(); console.log("1"); + tx = await pa2.transferOwnership(multisig); await tx.wait(); console.log("2"); + tx = await b.transferOwnership(multisig); await tx.wait(); console.log("3"); + tx = await x.transferOwnership(multisig); await tx.wait(); console.log("4"); + + } else throw ("Incorrect Network"); +}; + +async function main() { + await deployFactory(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); \ No newline at end of file diff --git a/scripts/setup-bridge.js b/scripts/setup-bridge.js index 2e04bee..26c3505 100644 --- a/scripts/setup-bridge.js +++ b/scripts/setup-bridge.js @@ -21,8 +21,8 @@ async function setupBridge(bridgeConfig) { if (bridgesToAdd !== undefined) { for (let i = 0; i < bridgesToAdd.length; i++) { try { - tx = await bridge.addBridge(bridgesToAdd[i].address, bridgesToAdd[i].destinationChainID); - await tx.wait(); + // tx = await bridge.addBridge(bridgesToAdd[i].address, bridgesToAdd[i].destinationChainID); + // await tx.wait(); console.log(`new bridge address: ${bridgesToAdd[i].address}; chainID: ${bridgesToAdd[i].destinationChainID} was added\n`); } catch (e) { console.warn(`the bridge ${bridgesToAdd[i].address} to ${bridgesToAdd[i].destinationChainID} was skipped`); @@ -43,8 +43,8 @@ async function setupBridge(bridgeConfig) { const destination = (await bridge.getDestination(originalTokenAddress, tokenToAdd[i].destinationChainID)).toString(); if (destination == "0x0000000000000000000000000000000000000000") { - tx = await bridge.addDestination(originalTokenAddress, tokenToAdd[i].destinationChainID, tokenToAdd[i].destinationAddress); - await tx.wait(); + // tx = await bridge.addDestination(originalTokenAddress, tokenToAdd[i].destinationChainID, tokenToAdd[i].destinationAddress); + // await tx.wait(); } const currentShortCap = (await bridge.shortCaps(originalTokenAddress)).toString(); diff --git a/tasks/deploy-xerc20-i.js b/tasks/deploy-xerc20-i.js new file mode 100644 index 0000000..8401f43 --- /dev/null +++ b/tasks/deploy-xerc20-i.js @@ -0,0 +1,198 @@ +const abiCoder = require("web3-eth-abi"); +const XERC_TEMPLATE_PATH = "./tasks/templates/xerc20.json"; + +let factoryAddress, deployer; + +let proxyAdminAddress; +let xERC20ImpAddr, lockboxImpAddr; + +task("deploy-xerc20-i", "it deploys the set of XERC20 contracts") + .addParam("execute", "whether deploy contracts or not (1 / 0)") + .setAction(async (taskArgs) => { + const { readJson } = require("../scripts/utils"); + + const execute = taskArgs["execute"]; + + const factoryPath = `./config/addresses/factory/${network.name}.json`; + factoryAddress = (await readJson(factoryPath)).factoryAddress; + if (factoryAddress.toString() == "") { + console.error("factory address is null"); + } + + const bridgePath = `./config/addresses/bridges/${network.name}.json`; + const bridgeAddress = (await readJson(bridgePath)).proxy; + if (bridgeAddress.toString() == "") { + console.error("bridge address is null"); + } + + const impsConfig = await readJson(`./tasks/templates/imps.json`); + await initializeImplementations(impsConfig); + + [d] = await ethers.getSigners(); + deployer = d; + + const configTemplate = await readJson(XERC_TEMPLATE_PATH); + const deployData = await generateCalldata(configTemplate); + + if (execute == "0") { + console.log(deployData); + } else { + const xerc20Address = await deploy(deployData); + await setAllowances(xerc20Address, bridgeAddress, configTemplate); + } + }); + +const deploy = async (deployCallData) => { + const xERC20Address = "0x9eFdE41A87fa4dD47BAa584954e8Abd5b8bdBfE7"; + console.log("xERC20 Address : " + xERC20Address); + + if (deployCallData.homeChain) { + const lockBoxAddress = "0xE075B9B12e41f8A0001FEEdA1C03E89418CA0cc0"; + console.log("Lockbox Address : " + lockBoxAddress); + + let xerc20 = await ethers.getContractAt("XERC20", xERC20Address); + let tx = await xerc20.setLockbox(lockBoxAddress); + await tx.wait(); + console.log("Lockbox is set"); + } + + return xERC20Address; +}; + +async function xERC20Calldata(name, symbol) { + const methodId = abiCoder.encodeFunctionSignature("initialize(string,string,address)"); + const params = abiCoder.encodeParameters(["string", "string", "address"], [name, symbol, factoryAddress]); + return methodId + params.substr(2); +} + +async function lockboxCalldata(xerc20, base, native) { + const methodId = abiCoder.encodeFunctionSignature("initialize(address,address,bool)"); + const params = abiCoder.encodeParameters(["address", "address", "bool"], [xerc20, base, native]); + return methodId + params.substr(2); +} + +async function deployXERC20Imp() { + + let xERC20ImplAddress = xERC20ImpAddr; + console.log(`XERC20 Impl address: ${xERC20ImplAddress}`); + + return xERC20ImplAddress; +} + +async function deployLockboxImp() { + + let lockboxImplAddress = lockboxImpAddr; + console.log(`Lockbox Impl address: ${lockboxImplAddress}`); + + return lockboxImplAddress; +} + +async function deployXERC20(xERC20Config) { + console.log("... Deploying xERC20 token ..."); + + const xERC20ImplAddress = await deployXERC20Imp(); + const factory = await hre.ethers.getContractAt("BridgeFactory", factoryAddress); + + console.log(`ProxyAdmin address: ${proxyAdminAddress}`); + + const ProxyFactory = await ethers.getContractFactory("InitializableTransparentUpgradeableProxy"); + + let XERC20SALT = ethers.solidityPackedKeccak256(["string", "string", "address"], [xERC20Config.tokenName, xERC20Config.tokenSymbol, await deployer.getAddress()]); + let BYTECODE = ethers.solidityPacked(["bytes"], [ProxyFactory.bytecode]); + + let tx = await factory.deployCreate3(BYTECODE, XERC20SALT); + const receipt = await tx.wait(); + let event = receipt.logs.find((e) => e.eventName === "ContractCreated"); + + console.log("Expected Address: " + event.args.addr); + + const calldata = await xERC20Calldata(xERC20Config.tokenName, xERC20Config.tokenSymbol) + const proxy = ProxyFactory.attach(event.args.addr); + tx = await proxy.initialize(xERC20ImplAddress, proxyAdminAddress, calldata); + await tx.wait(); + + return event.args.addr; +} + +async function deployLockBox(xERC20Address, baseTokenAddress) { + console.log("... Deploying Lockbox ..."); + + const lockboxImplAddress = await deployLockboxImp(); + const factory = await hre.ethers.getContractAt("BridgeFactory", factoryAddress); + + console.log(`ProxyAdmin address: ${proxyAdminAddress}`); + + const ProxyFactory = await ethers.getContractFactory("InitializableTransparentUpgradeableProxy"); + + let LOCKBOXSALT = ethers.solidityPackedKeccak256(["address", "address", "address"], [xERC20Address, baseTokenAddress, await deployer.getAddress()]); + let BYTECODE = ethers.solidityPacked(["bytes"], [ProxyFactory.bytecode]); + + let isNative = false; + let tx = await factory.deployCreate3(BYTECODE, LOCKBOXSALT); + const receipt = await tx.wait(); + const event = receipt.logs.find((e) => e.eventName === "ContractCreated"); + + console.log("Expected Address: " + event.args.addr); + + const calldata = await lockboxCalldata(xERC20Address, baseTokenAddress, isNative); + const proxy = ProxyFactory.attach(event.args.addr); + tx = await proxy.initialize(lockboxImplAddress, proxyAdminAddress, calldata); + await tx.wait(); + + return event.args.addr; +} + +async function setAllowances(xerc20Address, bridgeAddress, config) { + console.log("... Setting allowances ..."); + const xerc20 = await hre.ethers.getContractAt("XERC20", xerc20Address); + if (config.mintingAllowances == "" || config.mintingAllowances == "0") { + console.log("allowances are null"); + return; + } + if (config.burningAllowances == "" || config.burningAllowances == "0") { + console.log("allowances are null"); + return; + } + + let tx = await xerc20.setBridgeLimits(bridgeAddress, config.mintingAllowances, config.burningAllowances); + await tx.wait(); + console.log("Success"); +} + +const generateCalldata = async (configFile) => { + const config = require("dotenv").config(); + let originTokenAddress; + if (hre.network.name == "ethereum") { + originTokenAddress = config.parsed.ORIGIN_TOKEN_ADDRESS; + } + if (originTokenAddress == "") { + console.error("origin token address is null"); + } + /// get token name and symbol + let homeChain = false; + try { + const token = await hre.ethers.getContractAt("ERC20Mintable", originTokenAddress); + await token.name(); + homeChain = true; + } catch (err) { + // get from the config file -> destinationChain + homeChain = false; + } + + return { + homeChain: homeChain, + tokenAddress: originTokenAddress, + tokenName: configFile.tokenName, + tokenSymbol: configFile.tokenSymbol, + }; +}; + +const initializeImplementations = async (impsConfig) => { + const localChainID = network.config.chainId; + const data = impsConfig[localChainID]; + + xERC20ImpAddr = data["xERC20ImpAddr"]; + lockboxImpAddr = data["lockboxImpAddr"]; + proxyAdminAddress = data["proxyAdminAddress"]; +}; + \ No newline at end of file diff --git a/tasks/templates/bridge.json b/tasks/templates/bridge.json index b3eebd7..a1f4329 100644 --- a/tasks/templates/bridge.json +++ b/tasks/templates/bridge.json @@ -208,5 +208,23 @@ "longCap": "120000000000000000000" } ] + }, + "48900": { + "bridgeAddress": "0xC00cD5599F7E128FC5Ed5563147a45B12e83B3ac", + "bridgesToAdd": [ + { + "destinationChainID": "1", + "address": "0xC00cD5599F7E128FC5Ed5563147a45B12e83B3ac" + } + ], + "tokens": [ + { + "fromToken": "0x9eFdE41A87fa4dD47BAa584954e8Abd5b8bdBfE7", + "destinationChainID": "1", + "destinationAddress": "0x8E0789d39db454DBE9f4a77aCEF6dc7c69f6D552", + "shortCap": "50000000000000000000", + "longCap": "120000000000000000000" + } + ] } } diff --git a/tasks/templates/imps.json b/tasks/templates/imps.json new file mode 100644 index 0000000..7ac38a6 --- /dev/null +++ b/tasks/templates/imps.json @@ -0,0 +1,8 @@ +{ + "1": { + "xERC20ImpAddr" : "0xC9dc25eCA1a94DA3b69856a2211062f040a35477", + "lockboxImpAddr" : "0x4C858892DEcbF31460603f4bFC4620C328047f37", + "proxyAdminAddress" : "0x65Ab69857c23Cb65E713EfDAac930a892b161A67" + } +} + \ No newline at end of file diff --git a/tasks/templates/xerc20.json b/tasks/templates/xerc20.json index dda98e4..a3b63a6 100644 --- a/tasks/templates/xerc20.json +++ b/tasks/templates/xerc20.json @@ -1,6 +1,6 @@ { - "tokenName": "Inception Restaked cbETH", - "tokenSymbol": "IncbETH", + "tokenName": "Inception Symbiotic Restaked wstETH", + "tokenSymbol": "inwstETHs", "mintingAllowances": "1000000000000000000000", "burningAllowances": "1000000000000000000000" }