Skip to content

Commit 9453f74

Browse files
kumaryash90jnsdls
andauthored
Custom gas settings for any evm deployments (#2678)
Co-authored-by: Jonas Daniels <jonas.daniels@outlook.com>
1 parent bf6a8e0 commit 9453f74

File tree

8 files changed

+234
-88
lines changed

8 files changed

+234
-88
lines changed

.changeset/green-fireants-compete.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@thirdweb-dev/sdk": patch
3+
"thirdweb": patch
4+
---
5+
6+
Custom gas settings for any evm deployments

legacy_packages/sdk/src/evm/common/any-evm-constants.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,26 @@ export const ERROR_SUBSTRINGS_COMPOSITE = [
1919
["wrong", "chainid"],
2020
];
2121

22+
export const CUSTOM_GAS_BINS = [
23+
1,
24+
1 * 10 ** 9,
25+
100 * 10 ** 9,
26+
500 * 10 ** 9,
27+
1000 * 10 ** 9,
28+
2500 * 10 ** 9,
29+
5000 * 10 ** 9,
30+
7500 * 10 ** 9,
31+
10_000 * 10 ** 9,
32+
25_000 * 10 ** 9,
33+
50_000 * 10 ** 9,
34+
75_000 * 10 ** 9,
35+
100_000 * 10 ** 9,
36+
250_000 * 10 ** 9,
37+
500_000 * 10 ** 9,
38+
750_000 * 10 ** 9,
39+
1_000_000 * 10 ** 9,
40+
];
41+
2242
/* eslint-disable no-useless-computed-key */
2343
export const CUSTOM_GAS_FOR_CHAIN: Record<number, CustomChain> = {
2444
[5001]: {

legacy_packages/sdk/src/evm/common/any-evm-utils/deployCreate2Factory.ts

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
import { BigNumber, Signer } from "ethers";
1+
import { Signer } from "ethers";
22
import invariant from "tiny-invariant";
33
import type { DeployOptions } from "../../types/deploy/deploy-options";
4-
import { CUSTOM_GAS_FOR_CHAIN } from "../any-evm-constants";
5-
import { COMMON_FACTORY } from "./constants";
6-
import { isContractDeployed } from "./isContractDeployed";
7-
import { isEIP155Enforced } from "./isEIP155Enforced";
8-
import { getCreate2FactoryDeploymentInfo } from "./getCreate2FactoryDeploymentInfo";
4+
import { computeCreate2FactoryTransaction } from "./getCreate2FactoryAddress";
95

106
/**
117
* Deploy Nick's Create2 factory on a given network.
@@ -21,52 +17,19 @@ export async function deployCreate2Factory(
2117
options?: DeployOptions,
2218
): Promise<string> {
2319
invariant(signer.provider, "No provider");
24-
const commonFactoryExists = await isContractDeployed(
25-
COMMON_FACTORY,
20+
const deploymentInfo = await computeCreate2FactoryTransaction(
2621
signer.provider,
2722
);
28-
if (commonFactoryExists) {
29-
return COMMON_FACTORY;
30-
}
31-
32-
const enforceEip155 = await isEIP155Enforced(signer.provider);
33-
const networkId = (await signer.provider.getNetwork()).chainId;
34-
const chainId = enforceEip155 ? networkId : 0;
35-
console.debug(`ChainId ${networkId} enforces EIP155: ${enforceEip155}`);
36-
const deploymentInfo = CUSTOM_GAS_FOR_CHAIN[networkId]
37-
? getCreate2FactoryDeploymentInfo(chainId, {
38-
gasPrice: CUSTOM_GAS_FOR_CHAIN[networkId].gasPrice,
39-
gasLimit: CUSTOM_GAS_FOR_CHAIN[networkId].gasLimit,
40-
})
41-
: getCreate2FactoryDeploymentInfo(chainId, {});
42-
43-
const factoryExists = await isContractDeployed(
44-
deploymentInfo.deployment,
45-
signer.provider,
46-
);
47-
48-
// deploy community factory if not already deployed
49-
if (!factoryExists) {
50-
const gasPrice = CUSTOM_GAS_FOR_CHAIN[networkId]?.gasPrice
51-
? CUSTOM_GAS_FOR_CHAIN[networkId].gasPrice
52-
: 100 * 10 ** 9;
53-
const gasLimit = CUSTOM_GAS_FOR_CHAIN[networkId]?.gasLimit
54-
? CUSTOM_GAS_FOR_CHAIN[networkId].gasLimit
55-
: 100000;
56-
57-
invariant(gasLimit, "gasLimit undefined for create2 factory deploy");
58-
invariant(gasPrice, "gasPrice undefined for create2 factory deploy");
5923

24+
if (deploymentInfo.transaction.length > 0) {
6025
// send balance to the keyless signer
61-
const valueToSend = BigNumber.from(gasPrice).mul(gasLimit);
62-
6326
if (
64-
(await signer.provider.getBalance(deploymentInfo.signer)).lt(valueToSend)
27+
(await signer.provider.getBalance(deploymentInfo.signer)).lt(deploymentInfo.valueToSend)
6528
) {
6629
await (
6730
await signer.sendTransaction({
6831
to: deploymentInfo.signer,
69-
value: valueToSend,
32+
value: deploymentInfo.valueToSend,
7033
})
7134
).wait();
7235
}
Lines changed: 72 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { providers } from "ethers";
2-
import { CUSTOM_GAS_FOR_CHAIN } from "../any-evm-constants";
1+
import { BigNumber, providers } from "ethers";
2+
import { CUSTOM_GAS_BINS, CUSTOM_GAS_FOR_CHAIN } from "../any-evm-constants";
33
import { COMMON_FACTORY } from "./constants";
44
import { isContractDeployed } from "./isContractDeployed";
55
import { isEIP155Enforced } from "./isEIP155Enforced";
66
import { getCreate2FactoryDeploymentInfo } from "./getCreate2FactoryDeploymentInfo";
7+
import { KeylessDeploymentInfo } from "../../types/any-evm/deploy-data";
78

89
/**
910
* Get the CREATE2 Factory address for a network
@@ -16,23 +17,78 @@ import { getCreate2FactoryDeploymentInfo } from "./getCreate2FactoryDeploymentIn
1617
export async function getCreate2FactoryAddress(
1718
provider: providers.Provider,
1819
): Promise<string> {
19-
const commonFactoryExists = await isContractDeployed(
20-
COMMON_FACTORY,
21-
provider,
20+
const deploymentInfo = await computeCreate2FactoryTransaction(provider);
21+
return deploymentInfo.deployment;
22+
}
23+
24+
/**
25+
* @internal
26+
*/
27+
export async function computeCreate2FactoryTransaction(
28+
provider: providers.Provider,
29+
): Promise<KeylessDeploymentInfo> {
30+
const networkId = (await provider.getNetwork()).chainId;
31+
32+
// special handling for chains with hardcoded gasPrice and gasLimit
33+
if (CUSTOM_GAS_FOR_CHAIN[networkId]) {
34+
const enforceEip155 = await isEIP155Enforced(provider);
35+
const chainId = enforceEip155 ? networkId : 0;
36+
const gasPrice = CUSTOM_GAS_FOR_CHAIN[networkId]?.gasPrice;
37+
const gasLimit = CUSTOM_GAS_FOR_CHAIN[networkId]?.gasLimit;
38+
39+
const deploymentInfo = getCreate2FactoryDeploymentInfo(chainId, {
40+
gasPrice: gasPrice ? BigNumber.from(gasPrice) : undefined,
41+
gasLimit: gasLimit ? BigNumber.from(gasLimit) : undefined,
42+
});
43+
44+
if (await isContractDeployed(deploymentInfo.deployment, provider)) {
45+
deploymentInfo.transaction = "";
46+
}
47+
48+
return deploymentInfo;
49+
}
50+
51+
// default flow
52+
const allBinsInfo = [
53+
...CUSTOM_GAS_BINS.map((b) =>
54+
// to generate EIP-155 transaction
55+
getCreate2FactoryDeploymentInfo(networkId, { gasPrice: BigNumber.from(b) }),
56+
),
57+
// to generate pre-EIP-155 transaction, hence chainId 0
58+
...CUSTOM_GAS_BINS.map((b) =>
59+
getCreate2FactoryDeploymentInfo(0, { gasPrice: BigNumber.from(b) }),
60+
),
61+
];
62+
63+
const allFactories = await Promise.all(
64+
allBinsInfo.map((b) => isContractDeployed(b.deployment, provider)),
2265
);
23-
if (commonFactoryExists) {
24-
return COMMON_FACTORY;
66+
67+
const indexOfCommonFactory = allBinsInfo.findIndex(
68+
(b) => b.deployment === COMMON_FACTORY,
69+
);
70+
if (indexOfCommonFactory && allFactories[indexOfCommonFactory]) {
71+
return { ...allBinsInfo[indexOfCommonFactory], transaction: "" };
2572
}
2673

27-
const enforceEip155 = await isEIP155Enforced(provider);
28-
const networkId = (await provider.getNetwork()).chainId;
74+
const indexOfExistingDeployment = allFactories.findIndex((b) => b);
75+
if (indexOfExistingDeployment && allBinsInfo[indexOfExistingDeployment]) {
76+
return { ...allBinsInfo[indexOfExistingDeployment], transaction: "" };
77+
}
78+
79+
const [enforceEip155, gasPriceFetched] = await Promise.all([
80+
isEIP155Enforced(provider),
81+
provider.getGasPrice(),
82+
]);
2983
const chainId = enforceEip155 ? networkId : 0;
30-
const deploymentInfo = CUSTOM_GAS_FOR_CHAIN[networkId]
31-
? getCreate2FactoryDeploymentInfo(chainId, {
32-
gasPrice: CUSTOM_GAS_FOR_CHAIN[networkId].gasPrice,
33-
gasLimit: CUSTOM_GAS_FOR_CHAIN[networkId].gasLimit,
34-
})
35-
: getCreate2FactoryDeploymentInfo(chainId, {});
84+
const bin = _getNearestGasPriceBin(gasPriceFetched);
3685

37-
return deploymentInfo.deployment;
86+
return getCreate2FactoryDeploymentInfo(chainId, {
87+
gasPrice: bin,
88+
});
89+
}
90+
91+
function _getNearestGasPriceBin(gasPrice: BigNumber): BigNumber {
92+
const bin = CUSTOM_GAS_BINS.find((e) => BigNumber.from(e).gte(gasPrice));
93+
return bin ? BigNumber.from(bin) : gasPrice;
3894
}

legacy_packages/sdk/src/evm/common/any-evm-utils/getCreate2FactoryDeploymentInfo.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { utils } from "ethers";
1+
import { BigNumber, utils } from "ethers";
22
import { KeylessDeploymentInfo } from "../../types/any-evm/deploy-data";
33
import { SIGNATURE, CREATE2_FACTORY_BYTECODE } from "./constants";
44
import { getKeylessTxn } from "./getKeylessTxn";
@@ -11,13 +11,19 @@ import { getKeylessTxn } from "./getKeylessTxn";
1111
*/
1212
export function getCreate2FactoryDeploymentInfo(
1313
chainId: number,
14-
gasOptions: { gasPrice?: number; gasLimit?: number },
14+
gasOptions: { gasPrice?: BigNumber; gasLimit?: BigNumber },
1515
): KeylessDeploymentInfo {
1616
const signature = utils.joinSignature(SIGNATURE);
17+
18+
// 100000 is default deployment gas limit and 100 gwei is default gas price for create2 factory deployment
19+
// (See: https://github.com/Arachnid/deterministic-deployment-proxy?tab=readme-ov-file#deployment-gas-limit)
20+
const gasPrice = gasOptions.gasPrice ? gasOptions.gasPrice : 100 * 10 ** 9;
21+
const gasLimit = gasOptions.gasLimit ? gasOptions.gasLimit : 100000;
22+
1723
const deploymentTransaction = getKeylessTxn(
1824
{
19-
gasPrice: gasOptions.gasPrice ? gasOptions.gasPrice : 100 * 10 ** 9,
20-
gasLimit: gasOptions.gasLimit ? gasOptions.gasLimit : 100000,
25+
gasPrice,
26+
gasLimit,
2127
nonce: 0,
2228
data: CREATE2_FACTORY_BYTECODE,
2329
chainId: chainId,
@@ -32,5 +38,6 @@ export function getCreate2FactoryDeploymentInfo(
3238
return {
3339
...deploymentTransaction,
3440
deployment: create2FactoryAddress,
41+
valueToSend: BigNumber.from(gasPrice).mul(gasLimit),
3542
};
3643
}

legacy_packages/sdk/src/evm/types/any-evm/deploy-data.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BytesLike } from "ethers";
1+
import { BigNumber, BytesLike } from "ethers";
22
import { PreDeployMetadataFetched } from "../../schema/contracts/custom";
33
import { AddressOrEns } from "../../schema/shared/AddressOrEnsSchema";
44

@@ -24,6 +24,7 @@ export type KeylessDeploymentInfo = {
2424
signer: string;
2525
transaction: string;
2626
deployment: string;
27+
valueToSend: BigNumber;
2728
};
2829

2930
export type DeployedContractType =

legacy_packages/sdk/test/evm/any-evm-keyless.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,30 @@ import {
2626
englishAuctionsBytecode,
2727
englishAuctionsCompilerMetadata,
2828
} from "./mock/englishAuctionsMetadata";
29+
import { getCreate2FactoryAddress } from "../../src/evm/common/any-evm-utils/getCreate2FactoryAddress";
2930

3031
const itIf = (condition: boolean) => (condition ? it : it.skip);
3132

33+
describe("Create2 factory addresses", async () => {
34+
it("should compute correct addresses for create2 factory", async () => {
35+
// pre eip155
36+
sdk.updateSignerOrProvider(1);
37+
expect(await getCreate2FactoryAddress(sdk.getProvider())).to.equal("0x4e59b44847b379578588920cA78FbF26c0B4956C");
38+
39+
// eip155
40+
sdk.updateSignerOrProvider(923018);
41+
expect(await getCreate2FactoryAddress(sdk.getProvider())).to.equal("0x52329130FCBD4e15B0aC7C4505fBFB530b960AE8");
42+
43+
// eip155 with hardcoded custom gas
44+
sdk.updateSignerOrProvider(47);
45+
expect(await getCreate2FactoryAddress(sdk.getProvider())).to.equal("0x4F656d8f2e13D4980149940f4C962EC4f8aF31c5");
46+
47+
// eip155 with custom gas bin
48+
sdk.updateSignerOrProvider(2710);
49+
expect(await getCreate2FactoryAddress(sdk.getProvider())).to.equal("0x5Ffe7DeB88759a70B42bc12ABe16f72ce81F0459");
50+
})
51+
})
52+
3253
describe("Any EVM Keyless Deploy", async () => {
3354
let contract: SmartContract;
3455
let adminWallet: SignerWithAddress;

0 commit comments

Comments
 (0)