Skip to content

Commit

Permalink
feat: Deploy contracts with Axelar CREATE3 for deterministic addresses (
Browse files Browse the repository at this point in the history
#15)

* feat: Deploy Ojo and MockOjo contract with Axelar CREATE3 for deterministic deployment addresses

* Update hardhat.config.ts

* bracket (sorry ryan)

---------

Co-authored-by: Adam Wozniak <[email protected]>
  • Loading branch information
rbajollari and adamewozniak authored Jan 24, 2024
1 parent 638503c commit 430663e
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 35 deletions.
5 changes: 1 addition & 4 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1 @@
PRIVATE_KEY=
NETWORKS=POLYGON,EVMOS
POLYGON_URL=
EVMOS_URL=
PRIVATE_KEY=yourprivatekeyhere
3 changes: 2 additions & 1 deletion contracts/Ojo.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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_;
Expand Down
18 changes: 9 additions & 9 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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"]={
Expand Down
44 changes: 36 additions & 8 deletions scripts/deployMockOjo.ts
Original file line number Diff line number Diff line change
@@ -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) => {
Expand Down
49 changes: 38 additions & 11 deletions scripts/deployOjo.ts
Original file line number Diff line number Diff line change
@@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion test/MockOjo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
2 changes: 1 addition & 1 deletion test/Ojo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}
}
Expand Down
121 changes: 121 additions & 0 deletions testnet_chains.json
Original file line number Diff line number Diff line change
@@ -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"
}
]

0 comments on commit 430663e

Please sign in to comment.