diff --git a/.env.example b/.env.example index 95c6ad1..bedf8a3 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1 @@ -PRIVATE_KEY= -NETWORKS=POLYGON,EVMOS -POLYGON_URL= -EVMOS_URL= +PRIVATE_KEY=yourprivatekeyhere diff --git a/contracts/Ojo.sol b/contracts/Ojo.sol index 7b789dc..54ae75c 100644 --- a/contracts/Ojo.sol +++ b/contracts/Ojo.sol @@ -25,8 +25,9 @@ contract Ojo is IOjo, AxelarExecutable, Ownable { address gasReceiver_, string memory ojoChain_, string memory ojoAddress_, + address owner, uint256 resolveWindow_ - ) AxelarExecutable(gateway_) Ownable(msg.sender) { + ) AxelarExecutable(gateway_) Ownable(owner) { gasReceiver = IAxelarGasService(gasReceiver_); ojoChain = ojoChain_; ojoAddress = ojoAddress_; diff --git a/hardhat.config.ts b/hardhat.config.ts index 5470204..c5313fd 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,6 +1,6 @@ import { HardhatUserConfig } from "hardhat/config"; import "@nomicfoundation/hardhat-toolbox"; - +import testnet_chains from "./testnet_chains.json"; import "hardhat-abi-exporter"; import * as dotenv from 'dotenv'; @@ -9,14 +9,14 @@ let priv_key: string = process.env.PRIVATE_KEY || ""; function get_networks(){ let networks: any = {}; - if(process.env.NETWORKS){ - let network_list = process.env.NETWORKS.split(","); - network_list.forEach((network: string) => { - networks[network] = { - url: process.env[network + "_URL"] || "", - accounts: [priv_key] - } - }) + if(priv_key !== "") { + for (var chain of testnet_chains) { + networks[chain.name]={ + network_id: chain.chainId, + accounts: [priv_key], + url: chain.rpc + } + } } networks["hardhat"]={ diff --git a/scripts/deployMockOjo.ts b/scripts/deployMockOjo.ts index 413e890..ecef670 100644 --- a/scripts/deployMockOjo.ts +++ b/scripts/deployMockOjo.ts @@ -1,15 +1,43 @@ -import { ethers } from "hardhat"; +import { Wallet, AbiCoder, ethers } from "ethers"; +import MockOjo from '../artifacts/contracts/MockOjo.sol/MockOjo.json'; +import Create3Deployer from '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'; +import testnet_chains from '../testnet_chains.json'; async function main() { - const ojoContractddress = ""; + const ojoContractddress = "0x1cAe21620070E54C17279faDb2Bd6eBd5654459a"; + const create3DeployerAddress = "0x6513Aedb4D1593BA12e50644401D976aebDc90d8"; - const MockOjo = await ethers.getContractFactory("MockOjoContract"); - const mockOjo = await MockOjo.deploy(ojoContractddress); - await mockOjo.waitForDeployment(); + const privateKey = process.env.PRIVATE_KEY; - console.log( - `MockOjo deployed to ${await mockOjo.getAddress()}`, - ); + if (!privateKey) { + throw new Error('Invalid private key. Make sure the PRIVATE_KEY environment variable is set.'); + } + + const evmChains = testnet_chains.map((chain) => ({ ...chain })); + + for (const chain of evmChains) { + const provider = new ethers.JsonRpcProvider(chain.rpc) + const wallet = new Wallet(privateKey, provider); + const balance = await provider.getBalance(wallet.address) + console.log(`${chain.name} wallet balance: ${ethers.formatEther(balance.toString())} ${chain.tokenSymbol}`); + + const deployerContract = new ethers.Contract(create3DeployerAddress, Create3Deployer.abi, wallet); + + const salt = ethers.zeroPadValue(ethers.toUtf8Bytes("MockOjo"), 32); + + const coder = AbiCoder.defaultAbiCoder() + const creationCode = ethers.solidityPacked( + ["bytes", "bytes"], + [MockOjo.bytecode, coder.encode(["address"], [ojoContractddress])] + ); + + // perform static call to log address of the contract + const deployedAddress = await deployerContract.deploy.staticCallResult(creationCode, salt); + console.log(`${chain.name}, address: ${deployedAddress}`); + + // perform actual deploy tx + await deployerContract.deploy(creationCode, salt); + } } main().catch((error) => { diff --git a/scripts/deployOjo.ts b/scripts/deployOjo.ts index 2a32295..28a1b8b 100644 --- a/scripts/deployOjo.ts +++ b/scripts/deployOjo.ts @@ -1,19 +1,46 @@ -import { ethers } from "hardhat"; +import { Wallet, AbiCoder, ethers } from "ethers"; +import Ojo from '../artifacts/contracts/Ojo.sol/Ojo.json'; +import Create3Deployer from '@axelar-network/axelar-gmp-sdk-solidity/artifacts/contracts/deploy/Create3Deployer.sol/Create3Deployer.json'; +import testnet_chains from '../testnet_chains.json'; async function main() { - const axelarGatewayAddress = "0xe432150cce91c13a887f7D836923d5597adD8E31"; const axelarGasReceiverAddress = "0xbE406F0189A0B4cf3A05C286473D23791Dd44Cc6"; - const ojoChain = ""; - const ojoAddress = ""; - const resolveWindow = 1800 + const create3DeployerAddress = "0x6513Aedb4D1593BA12e50644401D976aebDc90d8"; + const ojoChain = "ojo"; + const ojoAddress = "ojo1es9mhmnunh208ucwq8rlrl97hqulxrz8k37dcu"; + const resolveWindow = 7200 - const Ojo = await ethers.getContractFactory("Ojo"); - const ojo = await Ojo.deploy(axelarGatewayAddress, axelarGasReceiverAddress, ojoChain, ojoAddress, resolveWindow); - await ojo.waitForDeployment(); + const privateKey = process.env.PRIVATE_KEY; - console.log( - `Ojo deployed to ${await ojo.getAddress()}\n`, - ); + if (!privateKey) { + throw new Error('Invalid private key. Make sure the PRIVATE_KEY environment variable is set.'); + } + + const evmChains = testnet_chains.map((chain) => ({ ...chain })); + + for (const chain of evmChains) { + const provider = new ethers.JsonRpcProvider(chain.rpc) + const wallet = new Wallet(privateKey, provider); + const balance = await provider.getBalance(wallet.address) + console.log(`${chain.name} wallet balance: ${ethers.formatEther(balance.toString())} ${chain.tokenSymbol}`); + + const deployerContract = new ethers.Contract(create3DeployerAddress, Create3Deployer.abi, wallet); + + const salt = ethers.zeroPadValue(ethers.toUtf8Bytes("Ojo"), 32); + + const coder = AbiCoder.defaultAbiCoder() + const creationCode = ethers.solidityPacked( + ["bytes", "bytes"], + [Ojo.bytecode, coder.encode(["address", "address", "string", "string", "address", "uint256"],[chain.gateway, axelarGasReceiverAddress, ojoChain, ojoAddress, wallet.address, resolveWindow])] + ); + + // perform static call to log address of the contract + const deployedAddress = await deployerContract.deploy.staticCallResult(creationCode, salt); + console.log(`${chain.name}, address: ${deployedAddress}`); + + // perform actual deploy tx + await deployerContract.deploy(creationCode, salt); + } } main().catch((error) => { diff --git a/test/MockOjo.ts b/test/MockOjo.ts index e183595..a6bbdf1 100644 --- a/test/MockOjo.ts +++ b/test/MockOjo.ts @@ -13,7 +13,7 @@ describe("Deploy", function () { const resolveWindow = 100; const Ojo = await ethers.getContractFactory("Ojo"); - const ojo = await Ojo.deploy(axelarGateway.address, axelarGasReceiver.address, ojoChain, ojoAddress, resolveWindow); + const ojo = await Ojo.deploy(axelarGateway.address, axelarGasReceiver.address, ojoChain, ojoAddress, deployer, resolveWindow); const MockOjo = await ethers.getContractFactory("MockOjo"); const mockOjo = await MockOjo.deploy(await ojo.getAddress()) diff --git a/test/Ojo.ts b/test/Ojo.ts index 9d5f02d..4b19801 100644 --- a/test/Ojo.ts +++ b/test/Ojo.ts @@ -12,7 +12,7 @@ describe("Deploy OjoContract", function () { const resolveWindow = 100; const Ojo = await ethers.getContractFactory("Ojo"); - const ojo = await Ojo.deploy(axelarGateway.address, axelarGasReceiver.address, ojoChain, ojoAddress, resolveWindow); + const ojo = await Ojo.deploy(axelarGateway.address, axelarGasReceiver.address, ojoChain, ojoAddress, deployer, resolveWindow); return {deployer, otherAccount, ojo} } diff --git a/testnet_chains.json b/testnet_chains.json new file mode 100644 index 0000000..4796e55 --- /dev/null +++ b/testnet_chains.json @@ -0,0 +1,121 @@ +[ + { + "name": "Ethereum Goerli", + "chainId": 5, + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "rpc": "https://goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161", + "tokenSymbol": "ETH" + }, + { + "name": "Ethereum Sepolia", + "chainId": 11155111, + "rpc": "https://1rpc.io/sepolia", + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "tokenSymbol": "ETH" + }, + { + "name": "BNB Chain", + "chainId": 97, + "gateway": "0x4D147dCb984e6affEEC47e44293DA442580A3Ec0", + "rpc": "https://data-seed-prebsc-1-s1.bnbchain.org:8545", + "tokenSymbol": "tBNB" + }, + { + "name": "Polygon Mumbai", + "chainId": 80001, + "gateway": "0xBF62ef1486468a6bd26Dd669C06db43dEd5B849B", + "rpc": "https://polygon-mumbai.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161", + "tokenSymbol": "MATIC" + }, + { + "name": "Polygon zkEVM", + "chainId": 1442, + "gateway": "0x999117D44220F33e0441fbAb2A5aDB8FF485c54D", + "rpc": "https://rpc.public.zkevm-test.net", + "tokenSymbol": "ETH" + }, + { + "name": "Avalanche Fuji C-Chain", + "chainId": 43113, + "rpc": "https://api.avax-test.network/ext/bc/C/rpc", + "gateway": "0xC249632c2D40b9001FE907806902f63038B737Ab", + "tokenSymbol": "AVAX" + }, + { + "name": "Fantom", + "chainId": 4002, + "gateway": "0x97837985Ec0494E7b9C71f5D3f9250188477ae14", + "rpc": "https://rpc.testnet.fantom.network", + "tokenSymbol": "FTM" + }, + { + "name": "Moonbase", + "chainId": 1287, + "rpc": "https://rpc.api.moonbase.moonbeam.network", + "gateway": "0x5769D84DD62a6fD969856c75c7D321b84d455929", + "tokenSymbol": "DEV" + }, + { + "name": "Arbitrum Goerli", + "chainId": 421613, + "rpc": "https://arbitrum-goerli.publicnode.com", + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "tokenSymbol": "AGOR" + }, + { + "name": "Arbitrum Sepolia", + "chainId": 421614, + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "rpc": "https://arbitrum-sepolia.blockpi.network/v1/rpc/public", + "tokenSymbol": "ETH" + }, + { + "name": "Optimism Goerli", + "chainId": 420, + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "rpc": "https://optimism-goerli.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161", + "tokenSymbol": "ETH" + }, + { + "name": "Base Goerli", + "chainId": 84531, + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "rpc": "https://goerli.base.org", + "tokenSymbol": "ETH" + }, + { + "name": "Mantle", + "chainId": 5001, + "rpc": "https://rpc.testnet.mantle.xyz", + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "tokenSymbol": "MNT" + }, + { + "name": "Alfajores", + "chainId": 44787, + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "rpc": "https://alfajores-forno.celo-testnet.org", + "tokenSymbol": "CELO" + }, + { + "name": "Kava", + "chainId": 2221, + "rpc": "https://evm.testnet.kava.io", + "gateway": "0xC8D18F85cB0Cee5C95eC29c69DeaF6cea972349c", + "tokenSymbol": "KAVA" + }, + { + "name": "Filecoin Calibration", + "chainId": 314159, + "gateway": "0x999117D44220F33e0441fbAb2A5aDB8FF485c54D", + "rpc": "https://rpc.ankr.com/filecoin_testnet", + "tokenSymbol": "FIL" + }, + { + "name": "Linea Goerli", + "chainId": 59140, + "gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31", + "rpc": "https://rpc.goerli.linea.build", + "tokenSymbol": "LineaETH" + } +]