Code Monkey home page Code Monkey logo

xdeployer's Introduction

xdeployer ๐Ÿ’ฅ

Test xdeploy License: MIT npm package

Hardhat plugin to deploy your smart contracts across multiple Ethereum Virtual Machine (EVM) chains with the same deterministic address.

Tip

It is pronounced cross-deployer.

What

This plugin will help you make easier and safer usage of the CREATE2 EVM opcode. CREATE2 can be used to compute in advance the address where a smart contract will be deployed, which allows for interesting new mechanisms known as counterfactual interactions.

Installation

With npm versions >=7:

# based on ethers v6
npm install --save-dev xdeployer

With npm version 6:

# based on ethers v6
npm install --save-dev xdeployer @nomicfoundation/hardhat-ethers ethers
Using ethers version 5

With npm versions >=7:

# based on ethers v5
npm install --save-dev 'xdeployer@^1.2.7'

With npm version 6:

# based on ethers v5
npm install --save-dev 'xdeployer@^1.2.7' @nomiclabs/hardhat-ethers 'ethers@^5.7.2' '@openzeppelin/contracts@^4.9.0'

Or if you are using Yarn:

# based on ethers v6
yarn add --dev xdeployer @nomicfoundation/hardhat-ethers ethers
Using ethers version 5
# based on ethers v5
yarn add --dev 'xdeployer@^1.2.7' @nomiclabs/hardhat-ethers 'ethers@^5.7.2' '@openzeppelin/contracts@^4.9.0'

In case you are using pnpm, invoke:

# based on ethers v6
pnpm add --save-dev xdeployer
Using ethers version 5
# based on ethers v5
pnpm add --save-dev 'xdeployer@^1.2.7'

Note

This plugin uses the optional chaining operator (?.). Optional chaining is not supported in Node.js v13 and below.

Import the plugin in your hardhat.config.js:

require("xdeployer");

Or if you are using TypeScript, in your hardhat.config.ts:

import "xdeployer";

Required Plugins

Tasks

This plugin provides the xdeploy task, which allows you to deploy your smart contracts across multiple EVM chains with the same deterministic address:

npx hardhat xdeploy

Environment Extensions

This plugin does not extend the environment.

Configuration

You need to add the following configurations to your hardhat.config.js file:

module.exports = {
  networks: {
    mainnet: { ... }
  },
  xdeploy: {
    contract: "YOUR_CONTRACT_NAME_TO_BE_DEPLOYED",
    constructorArgsPath: "PATH_TO_CONSTRUCTOR_ARGS", // optional; default value is `undefined`
    salt: "YOUR_SALT_MESSAGE",
    signer: "SIGNER_PRIVATE_KEY",
    networks: ["LIST_OF_NETWORKS"],
    rpcUrls: ["LIST_OF_RPCURLS"],
    gasLimit: 1_500_000, // optional; default value is `1.5e6`
  },
};

Or if you are using TypeScript, in your hardhat.config.ts:

const config: HardhatUserConfig = {
  networks: {
    mainnet: { ... }
  },
  xdeploy: {
    contract: "YOUR_CONTRACT_NAME_TO_BE_DEPLOYED",
    constructorArgsPath: "PATH_TO_CONSTRUCTOR_ARGS", // optional; default value is `undefined`
    salt: "YOUR_SALT_MESSAGE",
    signer: "SIGNER_PRIVATE_KEY",
    networks: ["LIST_OF_NETWORKS"],
    rpcUrls: ["LIST_OF_RPCURLS"],
    gasLimit: 1_500_000, // optional; default value is `1.5e6`
  },
};

The parameters constructorArgsPath and gasLimit are optional. The salt parameter is a random string value used to create the contract address. If you have previously deployed the same contract with the identical salt, the contract creation transaction will fail due to EIP-684. For more details, see also here.

Important

Please note that xdeployer computes the UTF-8 byte representation of the specified salt and calculates the keccak256 hash, which represents the 32-byte salt value that is passed to CREATE2.

Example:

xdeploy: {
    contract: "ERC20Mock",
    constructorArgsPath: "./deploy-args.ts",
    salt: "WAGMI",
    signer: vars.get("PRIVATE_KEY", ""),
    networks: ["hardhat", "sepolia", "holesky"],
    rpcUrls: [
      "hardhat",
      vars.get("ETH_SEPOLIA_TESTNET_URL", "https://rpc.sepolia.org"),
      vars.get("ETH_HOLESKY_TESTNET_URL", "https://holesky.rpc.thirdweb.com"),
    ],
    gasLimit: 1.2 * 10 ** 6,
},

Note

We recommend using Hardhat configuration variables introduced in Hardhat version 2.19.0 to set the private key of your signer.

The current available networks are:

  • Local:
    • localhost
    • hardhat
  • EVM-Based Test Networks:
    • sepolia
    • holesky
    • bscTestnet
    • optimismSepolia
    • arbitrumSepolia
    • amoy
    • polygonZkEVMTestnet
    • fantomTestnet
    • fuji
    • chiado
    • moonbaseAlpha
    • alfajores
    • auroraTestnet
    • harmonyTestnet
    • spark
    • cronosTestnet
    • evmosTestnet
    • bobaTestnet
    • cantoTestnet
    • baseSepolia
    • mantleTestnet
    • filecoinTestnet
    • scrollSepolia
    • lineaTestnet
    • zoraSepolia
    • luksoTestnet
    • mantaTestnet
    • blastTestnet
    • dosTestnet
    • fraxtalTestnet
    • metisTestnet
    • modeTestnet
    • seiArcticTestnet
    • xlayerTestnet
    • bobTestnet
    • coreTestnet
    • telosTestnet
    • rootstockTestnet
    • chilizTestnet
    • taraxaTestnet
  • EVM-Based Production Networks:
    • ethMain
    • bscMain
    • optimismMain
    • arbitrumOne
    • arbitrumNova
    • polygon
    • polygonZkEVMMain
    • fantomMain
    • avalanche
    • gnosis
    • moonriver
    • moonbeam
    • celo
    • auroraMain
    • harmonyMain
    • fuse
    • cronosMain
    • evmosMain
    • bobaMain
    • cantoMain
    • baseMain
    • mantleMain
    • filecoinMain
    • scrollMain
    • lineaMain
    • zoraMain
    • luksoMain
    • mantaMain
    • blastMain
    • dosMain
    • fraxtalMain
    • enduranceMain
    • kavaMain
    • metisMain
    • modeMain
    • xlayerMain
    • bobMain
    • coreMain
    • telosMain
    • rootstockMain
    • chilizMain
    • taraxaMain

Important

Note that you must ensure that your deployment account has sufficient funds on all target networks.

Local Deployment

If you also want to test deploy your smart contracts on "hardhat" or "localhost", you must first add the following Solidity file called Create2DeployerLocal.sol to your contracts/ folder:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

import { CreateX } from "xdeployer/src/contracts/CreateX.sol";

contract Create2DeployerLocal is CreateX {}

For this kind of deployment, you must set the Solidity version in the hardhat.config.js or hardhat.config.ts file to 0.8.23 or higher.

The RPC URL for hardhat is simply hardhat, while for localhost you must first run npx hardhat node, which defaults to http://127.0.0.1:8545. It is important to note that the local deployment does not generate the same deterministic address as on all live test/production networks, since the address of the smart contract that calls the opcode CREATE2 differs locally from the live test/production networks. I recommend using local deployments for general testing, for example to understand the correct gasLimit target size.

Further Considerations

The constructor arguments file must have an exportable field called data in case you are using TypeScript:

const data = [
  "arg1",
  "arg2",
  ...
];
export { data };

BigInt literals (e.g. 100_000_000_000_000_000_000n) can be used for the constructor arguments if you set target: ES2020 or higher in your tsconfig.json file. See also here for an example.

If you are using common JavaScript:

module.exports = [
  "arg1",
  "arg2",
  ...
];

The gasLimit field is set to 1'500'000 by default because the CREATE2 operations are a complex sequence of opcode executions. Usually the providers do not manage to estimate the gasLimit for these calls, so a predefined value is set.

The contract creation transaction is displayed on Etherscan (or any other block explorer) as a so-called internal transaction. An internal transaction is an action that is occurring within, or between, one or multiple smart contracts. In other words, it is initiated inside the code itself, rather than externally, from a wallet address controlled by a human. For more details on why it works this way, see here.

Warning

Solidity version 0.8.20 introduced support for the new opcode PUSH0, which was added as part of the Shanghai hard fork. Prior to running a deployment with a >=0.8.20-compiled bytecode (using the EVM version shanghai), please verify that all targeted EVM networks support the PUSH0 opcode. Otherwise, a deployment attempt on an EVM chain without PUSH0 support may result in deployment or runtime failure(s).

Warning

Solidity version 0.8.25 defaults to EVM version cancun, which features a number of new opcodes. Prior to running a deployment with a >=0.8.25-compiled bytecode (using the EVM version cancun), please verify that all targeted EVM networks support the new cancun opcodes. Otherwise, a deployment attempt on an EVM chain without cancun support may result in deployment or runtime failure(s).

Usage

npx hardhat xdeploy

Usage With Truffle

Truffle suite users can leverage the Hardhat plugin hardhat-truffle5 (or if you use Truffle v4 hardhat-truffle4) to integrate with TruffleContract from Truffle v5. This plugin allows tests and scripts written for Truffle to work with Hardhat.

How It Works

EVM opcodes can only be called via a smart contract. I have deployed a helper smart contract CreateX with the same address across all the available networks to make easier and safer usage of the CREATE2 EVM opcode. During your deployment, the plugin will call this contract.

A Note on SELFDESTRUCT

Using the CREATE2 EVM opcode always allows to redeploy a new smart contract to a previously selfdestructed contract address. However, if a contract creation is attempted, due to either a creation transaction or the CREATE/CREATE2 EVM opcode, and the destination address already has either nonzero nonce, or non-empty code, then the creation throws immediately, with exactly the same behavior as would arise if the first byte in the init code were an invalid opcode. This applies retroactively starting from genesis.

A Note on the Contract Creation Transaction

It is important to note that the msg.sender of the contract creation transaction is the helper smart contract CreateX with address 0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed. If you are relying on common smart contract libraries such as OpenZeppelin Contracts1 for your smart contract, which set certain constructor arguments to msg.sender (e.g. owner), you will need to change these arguments to tx.origin so that they are set to your deployer's EOA address. For another workaround, see here.

Caution

Please familiarise yourself with the security considerations concerning tx.origin. You can find more information about it, e.g. here.

Donation

I am a strong advocate of the open-source and free software paradigm. However, if you feel my work deserves a donation, you can send it to this address: 0x07bF3CDA34aA78d92949bbDce31520714AB5b228. I can pledge that I will use this money to help fix more existing challenges in the Ethereum ecosystem ๐Ÿค.

Footnotes

  1. Please note that OpenZeppelin Contracts version 5.0.0 has made the initial owner explicit (see PR #4267). โ†ฉ

xdeployer's People

Contributors

asghaier76 avatar dangerousfood avatar dependabot[bot] avatar pcaversaccio avatar renovate-bot avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

xdeployer's Issues

Solidity Version `0.8.20`

Add a remark in the README due to potential EVM equivalence issues triggered by the recently introduced PUSH0 opcode.

Add Fuse networks

To fully use xdeployer for the networks supported by Request Network protocol we will need to add Fuse networks and I can fund the deployer address on these networks after checking CREATE2 is existing there.

[Feature-Request]: Add Arbitrum Nova

Describe the desired feature:

Once I get access to the whitelist, I will add:

  • Arbitrum Nova Mainnet

Code example that solves the feature:

I will call it:

  • arbitrumNovaMain

Add further networks

We should add the following networks:

  • moonbeam
  • harmonyMain
  • harmonyTestnet
  • autobahn

๐Ÿ› `InvalidArgumentsError` With `signTypedData`

Describe the issue:

I have a hardhat test with signTypedData that starts to fail when I install xdeployer.

Code example to reproduce the issue:

import { ethers } from "hardhat";

const [signer] = await ethers.getSigners();
const domain = {
  name: 'Collateral',
  version: '2',
  chainId: 31337, // hardhat
  verifyingContract: '0xb0279Db6a2F1E01fbC8483FCCef0Be2bC6299cC3',
  salt: new Uint8Array([
    189, 181,  85, 137, 189, 110, 138, 202,
     85,  30, 222, 158, 181, 116,  29,  49,
    117,  28,  64, 185, 106, 101, 110, 218,
     99,  63,  69, 230, 136, 254,  92, 224
  ])
};
const type = {
  UpdateAdminThreshold: [
    { name: 'threshold', type: 'uint8' },
    { name: 'nonce', type: 'uint256' }
  ]
} ;
const data = { threshold: 1, nonce: 0n };

await signer.signTypedData(domain, type, data);

Version:

3.0.4.

Here are the rest

"@nomicfoundation/hardhat-chai-matchers": "^2.0.2",
"@nomicfoundation/hardhat-ethers": "^3.0.5",
"@nomicfoundation/hardhat-toolbox": "^3.0.0",
"ethers": "^6.8.1",
"hardhat": "^2.19.1",
"typescript": "^5.2.2",
"xdeployer": "^3.0.4"

Relevant log output:

InvalidArgumentsError: The message parameter is an invalid JSON. at line 1 column 776
      at EdrProviderWrapper.request (/Users/charlie/Code/rain-contract-v2/node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:423:10)

response.error looks like this.


{
  code: -32602,
  message: 'The message parameter is an invalid JSON. at line 1 column 776',
  data: {
    method: 'eth_signTypedData_v4',
    params: [
      '0x976ea74026e726554db657fa54763abd0c3a0aa9',
      '{"types":{"UpdateAdminThreshold":[{"name":"threshold","type":"uint8"},{"name":"nonce","type":"uint256"}],"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"},{"name":"salt","type":"bytes32"}]},"domain":{"name":"Collateral","version":"2","chainId":"0x7a69","verifyingContract":"0xb0279db6a2f1e01fbc8483fccef0be2bc6299cc3","salt":"0x54c6b2b3ad37d2ee0bf85cf73d4c147b0a1c333627a2cbf9a1bb9ecc1543fc7a"},"primaryType":"UpdateAdminThreshold","message":{"threshold":"1","nonce":"0"}}'
    ]
  }
}

๐Ÿฅน Base Mainnet Deployment; EDIT: As of `xdeployer` `v3.0.0`, `baseMain` Deployments Are Possible ๐Ÿป!

UPDATE: The predeploy of Create2Deployer is live on Base: 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2.

cast code 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2 --rpc-url https://mainnet.base.org

Returned bytecode:

0x6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033

The above bytecode that is predeployed got verified here: https://etherscan.io/address/0xF49600926c7109BD66Ab97a2c036bf696e58Dbc2#code. You can compare the compiled runtime bytecode and it will match.


TL;DR: Unfortunately, it is not possible to deploy the Create2Deployer contract on the Base production network.

Background

When bridging the funds to the Base mainnet, Base applied a recently introduced (but unfortunately unexpected) behaviour in the Bedrock upgrade that essentially sends a self transfer on L2. I.e. the nonce of the deployer account 0x554282cf65b42fc8fddc6041eb24ce5e8a0632ad was increased by 1 before deploying the Create2Deployer contract. Unfortunately, this means that I can no longer deploy the contract to 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2. If the demand for this chain is high enough, I might consider redeploying the Create2Deployer contract to a new address including the Base mainnet.

image

๐Ÿ’ฅ Add `seiArcticTestnet` Deployment

Describe the desired feature:

I have confirmed that seiArcticTestnet does conform to the standard CREATE2 behavior. Would you kindly deploy to seiArcticTestnet?

Code example that solves the feature:

No response

๐Ÿ› Polygon Deployment Throws With `transaction underpriced` Error

Describe the issue:

When deploying to Polygon mainnet contract deploy fails due to low gas limit while it has been set to the max allowed value 15e6
{\"jsonrpc\":\"2.0\",\"id\":55,\"error\":{\"code\":-32000,\"message\":\"transaction underpriced\"}}","error":{"code":-32000},"requestBody":"{\"method\":\"eth_sendRawTransaction\"
The

Code example to reproduce the issue:

xdeploy: {
    contract: 'ERC1155Factory',
    salt: 'DeploySalt',
    signer: process.env.PRIVATE_KEY,
    networks: [
      'polygon' 
  ],
    rpcUrls: [
      'https://polygon-mainnet.g.alchemy.com/v2/' + process.env.ALCHEMY_API_KEY
    ],
    gasLimit: 15_000_000 // optional; default value is `1.5e6`
  }

For Polygon average gaslimit reaches 30e6 so the hard limit of 15e6 might need to be updated

Version:

1.2.7

Relevant log output:

No response

Dependency Dashboard

This issue provides visibility into Renovate updates and their statuses. Learn more

Other Branches

These updates are pending. To force PRs open, click the checkbox below.

  • chore(deps): update dependency follow-redirects to 1.14.8 [security]
  • chore(deps): update dependency node-fetch to 2.6.7 [security]

  • Check this box to trigger a request for Renovate to run again on this repository

๐Ÿ’ฅ Support `@openzeppelin/hardhat-upgrades` Plugin

Describe the desired feature:

My contract uses Openzeppelin's upgradeable libs. I used to use @openzeppelin/hardhat-upgrades lib to deploy but I cannot really use it with xdeployer. The Openzeppelin lib does a lot of stuff especially for transparent proxy. It will save a lot of hassle if xdeployer and @openzeppelin/hardhat-upgrades can work together.

Thanks in advance!

Code example that solves the feature:

No response

Add `ethers` v6 support for `xdeployer`

Describe the desired feature:

This will be a breaking change! See Hardhat's release of @nomicfoundation/[email protected].

Also, need to add to the README:

Installation

npm install --save-dev xdeployer @nomicfoundation/hardhat-ethers ethers @openzeppelin/contracts

Or if you are using Yarn:

yarn add --dev xdeployer @nomicfoundation/hardhat-ethers ethers @openzeppelin/contracts

And update the peer dependencies accordingly.

Code example that solves the feature:

No response

Add Production Networks

Once the plugin is thoroughly tested on all the test networks, I will add the following production networks:

  • ethmain
  • bscmain
  • optimismmain
  • arbitrummain
  • polygon
  • hecoinfomain
  • fantommain
  • avalanche
  • gnosis
  • moonriver
  • celo

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.