-
Notifications
You must be signed in to change notification settings - Fork 194
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cli): deterministic deployer fallback (#2261)
- Loading branch information
Showing
17 changed files
with
319 additions
and
253 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@latticexyz/cli": patch | ||
--- | ||
|
||
Added a non-deterministic fallback for deploying to chains that have replay protection on and do not support pre-EIP-155 transactions (no chain ID). | ||
|
||
If you're using `mud deploy` and there's already a [deterministic deployer](https://github.com/Arachnid/deterministic-deployment-proxy) on your target chain, you can provide the address with `--deployerAddress 0x...` to still get some determinism. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,75 @@ | ||
import { Account, Chain, Client, Transport } from "viem"; | ||
import { getBytecode, sendRawTransaction, sendTransaction, waitForTransactionReceipt } from "viem/actions"; | ||
import { Account, Address, Chain, Client, Transport } from "viem"; | ||
import { getBalance, getBytecode, sendRawTransaction, sendTransaction, waitForTransactionReceipt } from "viem/actions"; | ||
import deployment from "./create2/deployment.json"; | ||
import { debug } from "./debug"; | ||
|
||
export const deployer = `0x${deployment.address}` as const; | ||
const deployer = `0x${deployment.address}` as const; | ||
const deployerBytecode = `0x${deployment.bytecode}` as const; | ||
|
||
export async function ensureDeployer(client: Client<Transport, Chain | undefined, Account>): Promise<void> { | ||
export async function ensureDeployer(client: Client<Transport, Chain | undefined, Account>): Promise<Address> { | ||
const bytecode = await getBytecode(client, { address: deployer }); | ||
if (bytecode) { | ||
debug("found create2 deployer at", deployer); | ||
return; | ||
debug("found CREATE2 deployer at", deployer); | ||
if (bytecode !== deployerBytecode) { | ||
console.warn( | ||
`\n ⚠️ Bytecode for deployer at ${deployer} did not match the expected CREATE2 bytecode. You may have unexpected results.\n` | ||
); | ||
} | ||
return deployer; | ||
} | ||
|
||
// send gas to signer | ||
debug("sending gas for create2 deployer to signer at", deployment.signerAddress); | ||
const gasTx = await sendTransaction(client, { | ||
chain: client.chain ?? null, | ||
to: `0x${deployment.signerAddress}`, | ||
value: BigInt(deployment.gasLimit) * BigInt(deployment.gasPrice), | ||
}); | ||
const gasReceipt = await waitForTransactionReceipt(client, { hash: gasTx }); | ||
if (gasReceipt.status !== "success") { | ||
console.error("failed to send gas to deployer signer", gasReceipt); | ||
throw new Error("failed to send gas to deployer signer"); | ||
// There's not really a way to simulate a pre-EIP-155 (no chain ID) transaction, | ||
// so we have to attempt to create the deployer first and, if it fails, fall back | ||
// to a regular deploy. | ||
|
||
// Send gas to deployment signer | ||
const gasRequired = BigInt(deployment.gasLimit) * BigInt(deployment.gasPrice); | ||
const currentBalance = await getBalance(client, { address: `0x${deployment.signerAddress}` }); | ||
const gasNeeded = gasRequired - currentBalance; | ||
if (gasNeeded > 0) { | ||
debug("sending gas for CREATE2 deployer to signer at", deployment.signerAddress); | ||
const gasTx = await sendTransaction(client, { | ||
chain: client.chain ?? null, | ||
to: `0x${deployment.signerAddress}`, | ||
value: gasNeeded, | ||
}); | ||
const gasReceipt = await waitForTransactionReceipt(client, { hash: gasTx }); | ||
if (gasReceipt.status !== "success") { | ||
console.error("failed to send gas to deployer signer", gasReceipt); | ||
throw new Error("failed to send gas to deployer signer"); | ||
} | ||
} | ||
|
||
// deploy the deployer | ||
debug("deploying create2 deployer at", deployer); | ||
const deployTx = await sendRawTransaction(client, { serializedTransaction: `0x${deployment.transaction}` }); | ||
// Deploy the deployer | ||
debug("deploying CREATE2 deployer at", deployer); | ||
const deployTx = await sendRawTransaction(client, { serializedTransaction: `0x${deployment.transaction}` }).catch( | ||
(error) => { | ||
// Do a regular contract create if the presigned transaction doesn't work due to replay protection | ||
if (String(error).includes("only replay-protected (EIP-155) transactions allowed over RPC")) { | ||
console.warn( | ||
// eslint-disable-next-line max-len | ||
`\n ⚠️ Your chain or RPC does not allow for non EIP-155 signed transactions, so your deploys will not be determinstic and contract addresses may change between deploys.\n\n We recommend running your chain's node with \`--rpc.allow-unprotected-txs\` to enable determinstic deployments.\n` | ||
); | ||
debug("deploying CREATE2 deployer"); | ||
return sendTransaction(client, { | ||
chain: client.chain ?? null, | ||
data: deployerBytecode, | ||
}); | ||
} | ||
throw error; | ||
} | ||
); | ||
|
||
const deployReceipt = await waitForTransactionReceipt(client, { hash: deployTx }); | ||
if (!deployReceipt.contractAddress) { | ||
throw new Error("Deploy receipt did not have contract address, was the deployer not deployed?"); | ||
} | ||
|
||
if (deployReceipt.contractAddress !== deployer) { | ||
console.error("unexpected contract address for deployer", deployReceipt); | ||
throw new Error("unexpected contract address for deployer"); | ||
console.warn( | ||
`\n ⚠️ CREATE2 deployer created at ${deployReceipt.contractAddress} does not match the CREATE2 determinstic deployer we expected (${deployer})` | ||
); | ||
} | ||
|
||
return deployReceipt.contractAddress; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.