diff --git a/CHANGELOG.md b/CHANGELOG.md index 1207a32..4454fac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.0.1-alpha.7 (2024-05-02) + +- Add options to enable overriding deployment transaction parameters. + ## 0.0.1-alpha.6 (2024-04-16) - Update documentation and error message about supported values for `--licenseType` option. ([#9](https://github.com/OpenZeppelin/defender-deploy-client-cli/pull/9)) diff --git a/README.md b/README.md index 3363de3..af09de4 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,10 @@ Additional options: --relayerId Relayer ID to use for deployment. Defaults to the relayer configured for your deployment environment on Defender. --salt Salt to use for CREATE2 deployment. Defaults to a random salt. --createFactoryAddress Address of the CREATE2 factory to use for deployment. Defaults to the factory provided by Defender. + --gasLimit Maximum amount of gas to allow the deployment transaction to use. + --gasPrice Gas price for legacy transactions, in wei. + --maxFeePerGas Maximum total fee per gas, in wei. + --maxPriorityFeePerGas Maximum priority fee per gas, in wei. ``` ### Proposing an upgrade diff --git a/package.json b/package.json index 644bb9f..1cb76d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/defender-deploy-client-cli", - "version": "0.0.1-alpha.6", + "version": "0.0.1-alpha.7", "description": "CLI for deployments using OpenZeppelin Defender SDK", "repository": "https://github.com/OpenZeppelin/defender-deploy-client-cli", "license": "MIT", diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index a533364..72cb4e7 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -2,7 +2,7 @@ import minimist from 'minimist'; import { FunctionArgs, deployContract } from '../internal/deploy-contract'; import { getDeployClient } from '../internal/client'; import { USAGE_COMMAND_PREFIX, getAndValidateString, getNetwork } from '../internal/utils'; -import { DeployClient } from '@openzeppelin/defender-sdk-deploy-client'; +import { DeployClient, TxOverrides } from '@openzeppelin/defender-sdk-deploy-client'; import { NetworkClient } from '@openzeppelin/defender-sdk-network-client'; const USAGE = `${USAGE_COMMAND_PREFIX} deploy --contractName --contractPath --chainId --buildInfoFile [--constructorBytecode ] [--licenseType ] [--verifySourceCode ] [--relayerId ] [--salt ] [--createFactoryAddress ]`; @@ -22,6 +22,10 @@ Additional options: --relayerId Relayer ID to use for deployment. Defaults to the relayer configured for your deployment environment on Defender. --salt Salt to use for CREATE2 deployment. Defaults to a random salt. --createFactoryAddress Address of the CREATE2 factory to use for deployment. Defaults to the factory provided by Defender. + --gasLimit Maximum amount of gas to allow the deployment transaction to use. + --gasPrice Gas price for legacy transactions, in wei. + --maxFeePerGas Maximum total fee per gas, in wei. + --maxPriorityFeePerGas Maximum priority fee per gas, in wei. `; export async function deploy(args: string[], deployClient?: DeployClient, networkClient?: NetworkClient): Promise { @@ -42,7 +46,8 @@ function parseArgs(args: string[]) { 'help', 'verifySourceCode', ], - string: ['contractName', 'contractPath', 'chainId', 'buildInfoFile', 'licenseType', 'constructorBytecode', 'relayerId', 'salt', 'createFactoryAddress'], + string: ['contractName', 'contractPath', 'chainId', 'buildInfoFile', 'licenseType', 'constructorBytecode', 'relayerId', 'salt', 'createFactoryAddress', 'gasLimit', 'gasPrice', 'maxFeePerGas', 'maxPriorityFeePerGas'], + alias: { h: 'help' }, default: { verifySourceCode: true }, }); @@ -86,9 +91,16 @@ async function getFunctionArgs(parsedArgs: minimist.ParsedArgs, extraArgs: strin const salt = getAndValidateString(parsedArgs, 'salt'); const createFactoryAddress = getAndValidateString(parsedArgs, 'createFactoryAddress'); + const txOverrides: TxOverrides = { + gasLimit: parseNumberOrUndefined(getAndValidateString(parsedArgs, 'gasLimit')), + gasPrice: parseHexOrUndefined(getAndValidateString(parsedArgs, 'gasPrice')), + maxFeePerGas: parseHexOrUndefined(getAndValidateString(parsedArgs, 'maxFeePerGas')), + maxPriorityFeePerGas: parseHexOrUndefined(getAndValidateString(parsedArgs, 'maxPriorityFeePerGas')), + }; + checkInvalidArgs(parsedArgs); - return { contractName, contractPath, network, buildInfoFile, licenseType, constructorBytecode, verifySourceCode, relayerId, salt, createFactoryAddress }; + return { contractName, contractPath, network, buildInfoFile, licenseType, constructorBytecode, verifySourceCode, relayerId, salt, createFactoryAddress, txOverrides }; } } @@ -109,9 +121,34 @@ function checkInvalidArgs(parsedArgs: minimist.ParsedArgs) { 'relayerId', 'salt', 'createFactoryAddress', + 'gasLimit', + 'gasPrice', + 'maxFeePerGas', + 'maxPriorityFeePerGas', ].includes(key), ); if (invalidArgs.length > 0) { throw new Error(`Invalid options: ${invalidArgs.join(', ')}`); } } + +function parseHexOrUndefined(value?: string): string | undefined { + if (value !== undefined) { + // If not a hex string, convert from decimal to hex as a string + if (!value.startsWith('0x')) { + return '0x' + Number(value).toString(16); + } else { + return value; + } + } else { + return undefined; + } +} + +function parseNumberOrUndefined(value?: string): number | undefined { + if (value !== undefined) { + return Number(value); + } else { + return undefined; + } +} \ No newline at end of file diff --git a/src/internal/deploy-contract.ts b/src/internal/deploy-contract.ts index e2caeb7..6aac19e 100644 --- a/src/internal/deploy-contract.ts +++ b/src/internal/deploy-contract.ts @@ -1,7 +1,7 @@ import { promises as fs } from 'fs'; import { Network } from '@openzeppelin/defender-sdk-base-client'; -import { DeployClient, DeployContractRequest, DeploymentResponse, SourceCodeLicense } from '@openzeppelin/defender-sdk-deploy-client'; +import { DeployClient, DeployContractRequest, DeploymentResponse, SourceCodeLicense, TxOverrides } from '@openzeppelin/defender-sdk-deploy-client'; export interface FunctionArgs { contractName: string; @@ -14,6 +14,7 @@ export interface FunctionArgs { relayerId?: string; salt?: string; createFactoryAddress?: string; + txOverrides?: TxOverrides; } export async function deployContract(args: FunctionArgs, client: DeployClient) { @@ -30,6 +31,7 @@ export async function deployContract(args: FunctionArgs, client: DeployClient) { relayerId: args.relayerId, salt: args.salt, createFactoryAddress: args.createFactoryAddress, + txOverrides: args.txOverrides, }; let deployment: DeploymentResponse; diff --git a/test/deploy.js b/test/deploy.js index 3579d90..78e2482 100644 --- a/test/deploy.js +++ b/test/deploy.js @@ -75,11 +75,32 @@ test('deploy required args', async t => { relayerId: undefined, salt: undefined, createFactoryAddress: undefined, + txOverrides: { + gasLimit: undefined, + gasPrice: undefined, + maxFeePerGas: undefined, + maxPriorityFeePerGas: undefined + }, }); }); test('deploy all args', async t => { - const args = ['--contractName', 'MyContract', '--contractPath', 'contracts/MyContract.sol', '--chainId', FAKE_CHAIN_ID, '--buildInfoFile', 'test/input/build-info.json', '--constructorBytecode', '0x1234', '--licenseType', 'MIT', '--verifySourceCode', 'false', '--relayerId', 'my-relayer-id', '--salt', '0x4567', '--createFactoryAddress', '0x0000000000000000000000000000000000098765']; + const args = [ + '--contractName', 'MyContract', + '--contractPath', 'contracts/MyContract.sol', + '--chainId', FAKE_CHAIN_ID, + '--buildInfoFile', 'test/input/build-info.json', + '--constructorBytecode', '0x1234', + '--licenseType', 'MIT', + '--verifySourceCode', 'false', + '--relayerId', 'my-relayer-id', + '--salt', '0x4567', + '--createFactoryAddress', '0x0000000000000000000000000000000000098765', + '--gasLimit', '1000000', + '--gasPrice', '1000000000', // 1 gwei + '--maxFeePerGas', '2000000000', // 2 gwei + '--maxPriorityFeePerGas', '500000000', // 0.5 gwei + ]; await deploy(args, t.context.fakeDeployClient, t.context.fakeNetworkClient); @@ -96,5 +117,11 @@ test('deploy all args', async t => { relayerId: 'my-relayer-id', salt: '0x4567', createFactoryAddress: '0x0000000000000000000000000000000000098765', + txOverrides: { + gasLimit: 1000000, + gasPrice: '0x3b9aca00', + maxFeePerGas: '0x77359400', + maxPriorityFeePerGas: '0x1dcd6500', + } }); }); \ No newline at end of file diff --git a/test/deploy.js.md b/test/deploy.js.md index 787d592..6c5254b 100644 --- a/test/deploy.js.md +++ b/test/deploy.js.md @@ -25,5 +25,9 @@ Generated by [AVA](https://avajs.dev). --relayerId Relayer ID to use for deployment. Defaults to the relayer configured for your deployment environment on Defender.␊ --salt Salt to use for CREATE2 deployment. Defaults to a random salt.␊ --createFactoryAddress Address of the CREATE2 factory to use for deployment. Defaults to the factory provided by Defender.␊ + --gasLimit Maximum amount of gas to allow the deployment transaction to use.␊ + --gasPrice Gas price for legacy transactions, in wei.␊ + --maxFeePerGas Maximum total fee per gas, in wei.␊ + --maxPriorityFeePerGas Maximum priority fee per gas, in wei.␊ ␊ ` diff --git a/test/deploy.js.snap b/test/deploy.js.snap index 23506f6..b0a7b4f 100644 Binary files a/test/deploy.js.snap and b/test/deploy.js.snap differ