From a38bfe9a671642cdfed9ba5df2b74664bfb4680e Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:10:31 +0200 Subject: [PATCH 01/13] add `DeployerMethodClass` --- packages/web3-eth-contract/src/contract.ts | 410 +++++++++++---------- 1 file changed, 221 insertions(+), 189 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index cba5043df95..09702a84a10 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -15,6 +15,8 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +/* eslint-disable max-classes-per-file */ + import { Web3Context, Web3EventEmitter, @@ -87,6 +89,7 @@ import { TransactionReceipt, FormatType, DecodedParams, + TransactionCall, } from 'web3-types'; import { format, @@ -215,6 +218,182 @@ const contractSubscriptions = { newBlockHeaders: NewHeadsSubscription, }; + +/* + * This class is only supposed to be used for the return of `new Contract(...).deploy(...)` method. + */ +export class DeployerMethodClass { + + protected readonly args: never[] | ContractConstructorArgs; + protected readonly constructorAbi: AbiConstructorFragment; + protected readonly contractOptions: ContractOptions; + protected readonly deployData?: string; + + protected _contractMethodDeploySend( + tx: TransactionCall, + ) { + // eslint-disable-next-line no-use-before-define + const returnTxOptions: SendTransactionOptions> = { + transactionResolver: (receipt: TransactionReceipt) => { + if (receipt.status === BigInt(0)) { + throw new Web3ContractError("code couldn't be stored", receipt); + } + + const newContract = this.parent.clone(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + newContract.options.address = receipt.contractAddress; + return newContract; + }, + + contractAbi: this.parent.options.jsonInterface, + // TODO Should make this configurable by the user + checkRevertBeforeSending: false, + }; + + return isNullish(this.parent.getTransactionMiddleware()) + ? sendTransaction(this.parent, tx, this.parent.defaultReturnFormat, returnTxOptions) // not calling this with undefined Middleware because it will not break if Eth package is not updated + : sendTransaction( + this.parent, + tx, + this.parent.defaultReturnFormat, + returnTxOptions, + this.parent.getTransactionMiddleware(), + ); + } + + public constructor( + // eslint-disable-next-line no-use-before-define + public parent: Contract, + public deployOptions: + | { + /** + * The byte code of the contract. + */ + data?: HexString; + input?: HexString; + /** + * The arguments which get passed to the constructor on deployment. + */ + arguments?: ContractConstructorArgs; + } + | undefined, + ) { + + const { args, abi, contractOptions, deployData} = this.calculateDeployParams(); + + this.args = args; + this.constructorAbi = abi; + this.contractOptions = contractOptions; + this.deployData = deployData; + } + + public send(options?: PayableTxOptions): ContractDeploySend { + const modifiedOptions = { ...options }; + + const tx = this.populateTransaction(modifiedOptions); + + return this._contractMethodDeploySend(tx); + } + + public populateTransaction( + txOptions?: PayableTxOptions | NonPayableTxOptions, + ) { + const modifiedContractOptions = { + ...this.contractOptions, + from: this.contractOptions.from ?? this.parent.defaultAccount ?? undefined, + }; + + // args, abi, contractOptions, deployData + + const tx = getSendTxParams({ + abi: this.constructorAbi, + params: this.args as unknown[], + options: { ...txOptions, dataInputFill: this.parent.contractDataInputFill }, + contractOptions: modifiedContractOptions, + }); + + // @ts-expect-error remove unnecessary field + if (tx.dataInputFill) { + // @ts-expect-error remove unnecessary field + delete tx.dataInputFill; + } + return tx; + } + + protected calculateDeployParams() { + let abi = this.parent.options.jsonInterface.find( + j => j.type === 'constructor', + ) as AbiConstructorFragment; + if (!abi) { + abi = { + type: 'constructor', + stateMutability: '', + } as AbiConstructorFragment; + } + + const _input = format( + { format: 'bytes' }, + this.deployOptions?.input ?? this.parent.options.input, + DEFAULT_RETURN_FORMAT, + ); + + const _data = format( + { format: 'bytes' }, + this.deployOptions?.data ?? this.parent.options.data, + DEFAULT_RETURN_FORMAT, + ); + + if ((!_input || _input.trim() === '0x') && (!_data || _data.trim() === '0x')) { + throw new Web3ContractError('contract creation without any data provided.'); + } + + const args = this.deployOptions?.arguments ?? []; + + const contractOptions: ContractOptions = { + ...this.parent.options, + input: _input, + data: _data, + }; + const deployData = _input ?? _data; + + return { args, abi, contractOptions, deployData} + } + + public async estimateGas( + options?: PayableCallOptions, + returnFormat: ReturnFormat = this.parent.defaultReturnFormat as ReturnFormat, + ) { + const modifiedOptions = { ...options }; + return this.parent.contractMethodEstimateGas({ + abi: this.constructorAbi as AbiFunctionFragment, + params: this.args as unknown[], + returnFormat, + options: modifiedOptions, + contractOptions: this.contractOptions, + }); + } + + public encodeABI() { + return encodeMethodABI( + this.constructorAbi, + this.args as unknown[], + format( + { format: 'bytes' }, + this.deployData as Bytes, + this.parent.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, + ), + ); + } + + public decodeData(data: HexString) { + return { + ...decodeMethodParams(this.constructorAbi, data.replace(this.deployData as string, ''), false), + __method__: this.constructorAbi.type, + }; + } +}; + /** * The `web3.eth.Contract` makes it easy to interact with smart contracts on the ethereum blockchain. * For using contract package, first install Web3 package using: `npm i web3` or `yarn add web3` based on your package manager, after that contracts features can be used as mentioned in following snippet. @@ -515,11 +694,7 @@ export class Contract ); public constructor( jsonInterface: Abi, - addressOrOptionsOrContext?: - | Address - | ContractInitOptions - | Web3ContractContext - | Web3Context, + addressOrOptionsOrContext?: Address | ContractInitOptions | Web3ContractContext | Web3Context, optionsOrContextOrReturnFormat?: | ContractInitOptions | Web3ContractContext @@ -545,20 +720,14 @@ export class Contract } let provider; - if ( - typeof addressOrOptionsOrContext === 'object' && - 'provider' in addressOrOptionsOrContext - ) { + if (typeof addressOrOptionsOrContext === 'object' && 'provider' in addressOrOptionsOrContext) { provider = addressOrOptionsOrContext.provider; } else if ( typeof optionsOrContextOrReturnFormat === 'object' && 'provider' in optionsOrContextOrReturnFormat ) { provider = optionsOrContextOrReturnFormat.provider; - } else if ( - typeof contextOrReturnFormat === 'object' && - 'provider' in contextOrReturnFormat - ) { + } else if (typeof contextOrReturnFormat === 'object' && 'provider' in contextOrReturnFormat) { provider = contextOrReturnFormat.provider; } else { provider = Contract.givenProvider; @@ -852,80 +1021,8 @@ export class Contract * The arguments which get passed to the constructor on deployment. */ arguments?: ContractConstructorArgs; - }) { - let abi = this._jsonInterface.find(j => j.type === 'constructor') as AbiConstructorFragment; - if (!abi) { - abi = { - type: 'constructor', - stateMutability: '', - } as AbiConstructorFragment; - } - - const _input = format( - { format: 'bytes' }, - deployOptions?.input ?? this.options.input, - DEFAULT_RETURN_FORMAT, - ); - - const _data = format( - { format: 'bytes' }, - deployOptions?.data ?? this.options.data, - DEFAULT_RETURN_FORMAT, - ); - - if ((!_input || _input.trim() === '0x') && (!_data || _data.trim() === '0x')) { - throw new Web3ContractError('contract creation without any data provided.'); - } - - const args = deployOptions?.arguments ?? []; - - const contractOptions: ContractOptions = { ...this.options, input: _input, data: _data }; - const deployData = _input ?? _data; - return { - arguments: args, - send: (options?: PayableTxOptions): ContractDeploySend => { - const modifiedOptions = { ...options }; - - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return this._contractMethodDeploySend( - abi as AbiFunctionFragment, - args as unknown[], - modifiedOptions, - contractOptions, - ); - }, - estimateGas: async ( - options?: PayableCallOptions, - returnFormat: ReturnFormat = this.defaultReturnFormat as ReturnFormat, - ) => { - const modifiedOptions = { ...options }; - return this._contractMethodEstimateGas({ - abi: abi as AbiFunctionFragment, - params: args as unknown[], - returnFormat, - options: modifiedOptions, - contractOptions, - }); - }, - encodeABI: () => - encodeMethodABI( - abi as AbiFunctionFragment, - args as unknown[], - format( - { format: 'bytes' }, - deployData as Bytes, - this.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, - ), - ), - decodeData: (data: HexString) => ({ - ...decodeMethodParams( - abi as AbiFunctionFragment, - data.replace(deployData as string, ''), - false, - ), - __method__: abi.type, // abi.type is constructor - }), - }; + }): DeployerMethodClass { + return new DeployerMethodClass(this, deployOptions); } /** @@ -1046,8 +1143,7 @@ export class Contract if (Array.isArray(filter[key])) { return (filter[key] as Numbers[]).some( (v: Numbers) => - String(log.returnValues[key]).toUpperCase() === - String(v).toUpperCase(), + String(log.returnValues[key]).toUpperCase() === String(v).toUpperCase(), ); } @@ -1057,10 +1153,7 @@ export class Contract if (hashedIndexedString === String(log.returnValues[key])) return true; } - return ( - String(log.returnValues[key]).toUpperCase() === - String(filter[key]).toUpperCase() - ); + return String(log.returnValues[key]).toUpperCase() === String(filter[key]).toUpperCase(); }); }); } @@ -1103,9 +1196,7 @@ export class Contract let result: ContractAbi = []; const functionsAbi = abis.filter(abi => abi.type !== 'error'); - const errorsAbi = abis.filter(abi => - isAbiErrorFragment(abi), - ) as unknown as AbiErrorFragment[]; + const errorsAbi = abis.filter(abi => isAbiErrorFragment(abi)) as unknown as AbiErrorFragment[]; for (const a of functionsAbi) { const abi: Mutable = { @@ -1121,9 +1212,7 @@ export class Contract // make constant and payable backwards compatible abi.constant = - abi.stateMutability === 'view' ?? - abi.stateMutability === 'pure' ?? - abi.constant; + abi.stateMutability === 'view' ?? abi.stateMutability === 'pure' ?? abi.constant; abi.payable = abi.stateMutability === 'payable' ?? abi.payable; this._overloadedMethodAbis.set(abi.name, [ @@ -1131,10 +1220,10 @@ export class Contract abi, ]); const abiFragment = this._overloadedMethodAbis.get(abi.name) ?? []; - const contractMethod = this._createContractMethod< - typeof abiFragment, - AbiErrorFragment - >(abiFragment, errorsAbi); + const contractMethod = this._createContractMethod( + abiFragment, + errorsAbi, + ); const exactContractMethod = this._createContractMethod< typeof abiFragment, @@ -1147,8 +1236,7 @@ export class Contract }; // We don't know a particular type of the Abi method so can't type check - this._methods[abi.name as keyof ContractMethodsInterface] = - contractMethod as never; + this._methods[abi.name as keyof ContractMethodsInterface] = contractMethod as never; // We don't know a particular type of the Abi method so can't type check this._methods[methodName as keyof ContractMethodsInterface] = @@ -1224,10 +1312,7 @@ export class Contract for (const _abi of arrayOfAbis) { try { abiParams = this._getAbiParams(_abi, params); - validator.validate( - _abi.inputs as unknown as ValidationSchemaInput, - abiParams, - ); + validator.validate(_abi.inputs as unknown as ValidationSchemaInput, abiParams); applicableMethodAbi.push(_abi); } catch (e) { errors.push(e as Web3ValidationErrorObject); @@ -1243,9 +1328,9 @@ export class Contract } compatible methods: ${JSON.stringify( applicableMethodAbi.map( m => - `${ - (m as { methodNameWithInputs: string }).methodNameWithInputs - } (signature: ${(m as { signature: string }).signature})`, + `${(m as { methodNameWithInputs: string }).methodNameWithInputs} (signature: ${ + (m as { signature: string }).signature + })`, ), )} \n\tThe first one will be used: ${ (methodAbi as { methodNameWithInputs: string }).methodNameWithInputs @@ -1267,14 +1352,7 @@ export class Contract call: async ( options?: PayableCallOptions | NonPayableCallOptions, block?: BlockNumberOrTag, - ) => - this._contractMethodCall( - methodAbi, - abiParams, - internalErrorsAbis, - options, - block, - ), + ) => this._contractMethodCall(methodAbi, abiParams, internalErrorsAbis, options, block), send: (options?: PayableTxOptions | NonPayableTxOptions): ContractMethodSend => this._contractMethodSend(methodAbi, abiParams, internalErrorsAbis, options), @@ -1303,10 +1381,9 @@ export class Contract }, estimateGas: async ( options?: PayableCallOptions | NonPayableCallOptions, - returnFormat: ReturnFormat = this - .defaultReturnFormat as unknown as ReturnFormat, + returnFormat: ReturnFormat = this.defaultReturnFormat as unknown as ReturnFormat, ) => - this._contractMethodEstimateGas({ + this.contractMethodEstimateGas({ abi: methodAbi, params: abiParams, returnFormat, @@ -1428,17 +1505,23 @@ export class Contract contractOptions: modifiedContractOptions, }); - const transactionToSend = (isNullish(this.transactionMiddleware)) ? - sendTransaction(this, tx, this.defaultReturnFormat, { - // TODO Should make this configurable by the user - checkRevertBeforeSending: false, - contractAbi: this._jsonInterface, // explicitly not passing middleware so if some one is using old eth package it will not break - }) : - sendTransaction(this, tx, this.defaultReturnFormat, { - // TODO Should make this configurable by the user - checkRevertBeforeSending: false, - contractAbi: this._jsonInterface, - }, this.transactionMiddleware); + const transactionToSend = isNullish(this.transactionMiddleware) + ? sendTransaction(this, tx, this.defaultReturnFormat, { + // TODO Should make this configurable by the user + checkRevertBeforeSending: false, + contractAbi: this._jsonInterface, // explicitly not passing middleware so if some one is using old eth package it will not break + }) + : sendTransaction( + this, + tx, + this.defaultReturnFormat, + { + // TODO Should make this configurable by the user + checkRevertBeforeSending: false, + contractAbi: this._jsonInterface, + }, + this.transactionMiddleware, + ); // eslint-disable-next-line no-void void transactionToSend.on('error', (error: unknown) => { @@ -1450,48 +1533,7 @@ export class Contract return transactionToSend; } - private _contractMethodDeploySend( - abi: AbiFunctionFragment, - params: unknown[], - options?: Options, - contractOptions?: ContractOptions, - ) { - let modifiedContractOptions = contractOptions ?? this.options; - modifiedContractOptions = { - ...modifiedContractOptions, - from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined, - }; - const tx = getSendTxParams({ - abi, - params, - options: { ...options, dataInputFill: this.contractDataInputFill }, - contractOptions: modifiedContractOptions, - }); - - const returnTxOptions: SendTransactionOptions> = { - transactionResolver: (receipt: TransactionReceipt) => { - if (receipt.status === BigInt(0)) { - throw new Web3ContractError("code couldn't be stored", receipt); - } - - const newContract = this.clone(); - - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - newContract.options.address = receipt.contractAddress; - return newContract; - }, - contractAbi: this._jsonInterface, - // TODO Should make this configurable by the user - checkRevertBeforeSending: false, - }; - - return ( - (isNullish(this.transactionMiddleware)) ? - sendTransaction(this, tx, this.defaultReturnFormat, returnTxOptions) : // not calling this with undefined Middleware because it will not break if Eth package is not updated - sendTransaction(this, tx, this.defaultReturnFormat, returnTxOptions, this.transactionMiddleware)); - } - - private async _contractMethodEstimateGas< + public async contractMethodEstimateGas< Options extends PayableCallOptions | NonPayableCallOptions, ReturnFormat extends DataFormat, >({ @@ -1522,11 +1564,7 @@ export class Contract returnFormat: DataFormat = this.defaultReturnFormat, ): ContractBoundEvent { return (...params: unknown[]) => { - const { topics, fromBlock } = encodeEventABI( - this.options, - abi, - params[0] as EventParameters, - ); + const { topics, fromBlock } = encodeEventABI(this.options, abi, params[0] as EventParameters); const sub = new LogsSubscription( { address: this.options.address, @@ -1536,10 +1574,7 @@ export class Contract }, { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - subscriptionManager: this.subscriptionManager as Web3SubscriptionManager< - unknown, - any - >, + subscriptionManager: this.subscriptionManager as Web3SubscriptionManager, returnFormat, }, ); @@ -1552,10 +1587,7 @@ export class Contract } }) .catch((error: Error) => { - sub.emit( - 'error', - new SubscriptionError('Failed to get past events.', error), - ); + sub.emit('error', new SubscriptionError('Failed to get past events.', error)); }); } this.subscriptionManager?.addSubscription(sub).catch((error: Error) => { From dff500bd093119baaacdce93bbb46ca7c2a42b82 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:11:02 +0200 Subject: [PATCH 02/13] set `extraTxTypes` using global --- .../web3-eth-accounts/src/tx/transactionFactory.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth-accounts/src/tx/transactionFactory.ts b/packages/web3-eth-accounts/src/tx/transactionFactory.ts index a677543c64f..98a465c0973 100644 --- a/packages/web3-eth-accounts/src/tx/transactionFactory.ts +++ b/packages/web3-eth-accounts/src/tx/transactionFactory.ts @@ -31,7 +31,15 @@ import type { } from './types.js'; import { BaseTransaction } from './baseTransaction.js'; -const extraTxTypes: Map> = new Map(); +let extraTxTypes: Map>; +// use the global object, to work fine even if web3-eth and web3-eth-accounts was on a different versions: +const typedGlobal = global as unknown as {extraTxTypes: Map>} +if (!typedGlobal.extraTxTypes) { + extraTxTypes = new Map(); + typedGlobal.extraTxTypes = extraTxTypes; +} else { + extraTxTypes = typedGlobal.extraTxTypes; +} // eslint-disable-next-line @typescript-eslint/no-extraneous-class export class TransactionFactory { From 4f442f9d1253af35c8a139e839af7889290c3c71 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:12:06 +0200 Subject: [PATCH 03/13] comment `validateGas` at `validateTransactionForSigning` --- packages/web3-eth/src/validation.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth/src/validation.ts b/packages/web3-eth/src/validation.ts index a818cc66c10..3601cb49c8a 100644 --- a/packages/web3-eth/src/validation.ts +++ b/packages/web3-eth/src/validation.ts @@ -297,7 +297,9 @@ export const validateTransactionForSigning = ( validateHardfork(transaction); const formattedTransaction = formatTransaction(transaction as Transaction, ETH_DATA_FORMAT); - validateGas(formattedTransaction); + + // TODO: uncomment and make it optional + // validateGas(formattedTransaction); if ( isNullish(formattedTransaction.nonce) || From 705e660ea1f6204913771319cd952495709714d6 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:13:11 +0200 Subject: [PATCH 04/13] make `getBaseFee` and `getDataFee` return 0n if common was not available --- packages/web3-eth-accounts/src/tx/baseTransaction.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/web3-eth-accounts/src/tx/baseTransaction.ts b/packages/web3-eth-accounts/src/tx/baseTransaction.ts index 5762b8889e9..661306f5e61 100644 --- a/packages/web3-eth-accounts/src/tx/baseTransaction.ts +++ b/packages/web3-eth-accounts/src/tx/baseTransaction.ts @@ -215,6 +215,9 @@ export abstract class BaseTransaction { * The minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee) */ public getBaseFee(): bigint { + if( !this.common ) { + return BigInt(0); + } const txFee = this.common.param('gasPrices', 'tx'); let fee = this.getDataFee(); if (txFee) fee += txFee; @@ -229,6 +232,9 @@ export abstract class BaseTransaction { * The amount of gas paid for the data in this tx */ public getDataFee(): bigint { + if( !this.common ) { + return BigInt(0); + } const txDataZero = this.common.param('gasPrices', 'txDataZero'); const txDataNonZero = this.common.param('gasPrices', 'txDataNonZero'); From be87e7f34590ef38711394dde059e66d01ccf893 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:16:10 +0200 Subject: [PATCH 05/13] make `from` as optional at `getSendTxParams` --- packages/web3-eth-contract/src/utils.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 748203ffdf7..bedd8408cad 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -76,15 +76,16 @@ export const getSendTxParams = ({ throw new Web3ContractError('Contract address not specified'); } - if (!options?.from && !contractOptions.from) { - throw new Web3ContractError('Contract "from" address not specified'); - } + // in case of preparing a tx to be sent later by some other account, 'from' is not required + // TODO: is it OK to remove this check? + // if (!options?.from && !contractOptions.from) { + // throw new Web3ContractError('Contract "from" address not specified'); + // } let txParams = mergeDeep( { to: contractOptions.address, gas: contractOptions.gas, gasPrice: contractOptions.gasPrice, - from: contractOptions.from, input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, @@ -92,6 +93,11 @@ export const getSendTxParams = ({ }, options as unknown as Record, ) as unknown as TransactionCall; + // Because of the next condition, in case 'from' is not provided in contractOptions, + // the 'txParams.from' will not be undefined. + if (contractOptions.from) { + txParams.from = contractOptions.from + } const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; From 45542fd2e6fea2fec3be4a64d3b05333da75c6f5 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:16:58 +0200 Subject: [PATCH 06/13] fix a type (related to contract deployment) --- packages/web3-eth-contract/src/utils.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index bedd8408cad..9e12cb37e00 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -28,6 +28,7 @@ import { PayableCallOptions, ContractOptions, Numbers, + AbiConstructorFragment, } from 'web3-types'; import { isNullish, mergeDeep, isContractInitOptions, keccak256, toChecksumAddress, hexToNumber } from 'web3-utils'; import { isAddress, isHexString } from 'web3-validator'; @@ -36,7 +37,7 @@ import { Web3ContractContext } from './types.js'; const dataInputEncodeMethodHelper = ( txParams: TransactionCall | TransactionForAccessList, - abi: AbiFunctionFragment, + abi: AbiFunctionFragment | AbiConstructorFragment, params: unknown[], dataInputFill?: 'data' | 'input' | 'both', ): { data?: HexString; input?: HexString } => { @@ -60,7 +61,7 @@ export const getSendTxParams = ({ options, contractOptions, }: { - abi: AbiFunctionFragment; + abi: AbiFunctionFragment | AbiConstructorFragment; params: unknown[]; options?: (PayableCallOptions | NonPayableCallOptions) & { input?: HexString; From 5b017d5dc4eb2bc55135dc11c1c5f9acb5dcef45 Mon Sep 17 00:00:00 2001 From: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Tue, 20 Aug 2024 23:24:27 +0200 Subject: [PATCH 07/13] revert some validation changes --- .../web3-eth-accounts/src/tx/baseTransaction.ts | 6 ------ packages/web3-eth-contract/src/utils.ts | 14 ++++---------- packages/web3-eth/src/validation.ts | 4 +--- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/packages/web3-eth-accounts/src/tx/baseTransaction.ts b/packages/web3-eth-accounts/src/tx/baseTransaction.ts index 661306f5e61..5762b8889e9 100644 --- a/packages/web3-eth-accounts/src/tx/baseTransaction.ts +++ b/packages/web3-eth-accounts/src/tx/baseTransaction.ts @@ -215,9 +215,6 @@ export abstract class BaseTransaction { * The minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee) */ public getBaseFee(): bigint { - if( !this.common ) { - return BigInt(0); - } const txFee = this.common.param('gasPrices', 'tx'); let fee = this.getDataFee(); if (txFee) fee += txFee; @@ -232,9 +229,6 @@ export abstract class BaseTransaction { * The amount of gas paid for the data in this tx */ public getDataFee(): bigint { - if( !this.common ) { - return BigInt(0); - } const txDataZero = this.common.param('gasPrices', 'txDataZero'); const txDataNonZero = this.common.param('gasPrices', 'txDataNonZero'); diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts index 9e12cb37e00..fc475a5a813 100644 --- a/packages/web3-eth-contract/src/utils.ts +++ b/packages/web3-eth-contract/src/utils.ts @@ -77,16 +77,15 @@ export const getSendTxParams = ({ throw new Web3ContractError('Contract address not specified'); } - // in case of preparing a tx to be sent later by some other account, 'from' is not required - // TODO: is it OK to remove this check? - // if (!options?.from && !contractOptions.from) { - // throw new Web3ContractError('Contract "from" address not specified'); - // } + if (!options?.from && !contractOptions.from) { + throw new Web3ContractError('Contract "from" address not specified'); + } let txParams = mergeDeep( { to: contractOptions.address, gas: contractOptions.gas, gasPrice: contractOptions.gasPrice, + from: contractOptions.from, input: contractOptions.input, maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas, maxFeePerGas: contractOptions.maxFeePerGas, @@ -94,11 +93,6 @@ export const getSendTxParams = ({ }, options as unknown as Record, ) as unknown as TransactionCall; - // Because of the next condition, in case 'from' is not provided in contractOptions, - // the 'txParams.from' will not be undefined. - if (contractOptions.from) { - txParams.from = contractOptions.from - } const dataInput = dataInputEncodeMethodHelper(txParams, abi, params, options?.dataInputFill); txParams = { ...txParams, data: dataInput.data, input: dataInput.input }; diff --git a/packages/web3-eth/src/validation.ts b/packages/web3-eth/src/validation.ts index 3601cb49c8a..a818cc66c10 100644 --- a/packages/web3-eth/src/validation.ts +++ b/packages/web3-eth/src/validation.ts @@ -297,9 +297,7 @@ export const validateTransactionForSigning = ( validateHardfork(transaction); const formattedTransaction = formatTransaction(transaction as Transaction, ETH_DATA_FORMAT); - - // TODO: uncomment and make it optional - // validateGas(formattedTransaction); + validateGas(formattedTransaction); if ( isNullish(formattedTransaction.nonce) || From 94854859f70ec128daf10f9cdc2f2f747fc762c6 Mon Sep 17 00:00:00 2001 From: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:14:03 +0200 Subject: [PATCH 08/13] update CHANGELOG.md files --- packages/web3-eth-accounts/CHANGELOG.md | 3 +++ packages/web3-eth-contract/CHANGELOG.md | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/packages/web3-eth-accounts/CHANGELOG.md b/packages/web3-eth-accounts/CHANGELOG.md index b28e2c9b047..b682b5e34bb 100644 --- a/packages/web3-eth-accounts/CHANGELOG.md +++ b/packages/web3-eth-accounts/CHANGELOG.md @@ -172,3 +172,6 @@ Documentation: ### Added - Added public function `signMessageWithPrivateKey` (#7174) + +### Fixed +- Fix `TransactionFactory.registerTransactionType` not working, if there is a version mistatch between `web3-eth` and `web3-eth-accounts` by saving `extraTxTypes` at `globals`. (#7197) diff --git a/packages/web3-eth-contract/CHANGELOG.md b/packages/web3-eth-contract/CHANGELOG.md index bab02912320..01e6f2f8a68 100644 --- a/packages/web3-eth-contract/CHANGELOG.md +++ b/packages/web3-eth-contract/CHANGELOG.md @@ -395,3 +395,11 @@ Documentation: ## [Unreleased] +### Added + +- Added `populateTransaction` to the `contract.deploy(...)` properties. (#7197) + +### Changed + +- The returnred properties of `contract.deploy(...)` are structured with a newly created class named `DeployerMethodClass`. (#7197) +- Add a missed accepted type for the `abi` parameter, at `dataInputEncodeMethodHelper` and `getSendTxParams`. (#7197) From ae250d786469da3559e9f793fb42487b306c9675 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Wed, 21 Aug 2024 16:45:15 +0200 Subject: [PATCH 09/13] add DeployerMethodClass into a separate file --- .../src/contract-deployer-method-class.ts | 239 ++++++++++++++++++ packages/web3-eth-contract/src/contract.ts | 186 +------------- packages/web3-eth-contract/src/index.ts | 1 + 3 files changed, 241 insertions(+), 185 deletions(-) create mode 100644 packages/web3-eth-contract/src/contract-deployer-method-class.ts diff --git a/packages/web3-eth-contract/src/contract-deployer-method-class.ts b/packages/web3-eth-contract/src/contract-deployer-method-class.ts new file mode 100644 index 00000000000..751d50d1113 --- /dev/null +++ b/packages/web3-eth-contract/src/contract-deployer-method-class.ts @@ -0,0 +1,239 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { + Web3ContractError, +} from 'web3-errors'; +import { + sendTransaction, + SendTransactionEvents, + SendTransactionOptions, +} from 'web3-eth'; +import { + AbiConstructorFragment, + AbiFunctionFragment, + ContractAbi, + ContractConstructorArgs, + Bytes, + HexString, + PayableCallOptions, + DataFormat, + DEFAULT_RETURN_FORMAT, + ContractOptions, + TransactionReceipt, + TransactionCall, +} from 'web3-types'; +import { + format, +} from 'web3-utils'; +import { + isNullish, +} from 'web3-validator'; +import { Web3PromiEvent } from 'web3-core'; +import { + decodeMethodParams, + encodeMethodABI, +} from './encoding.js'; +import { + NonPayableTxOptions, + PayableTxOptions, +} from './types.js'; +import { + getSendTxParams, +} from './utils.js'; +import { Contract } from './contract.js'; + +export type ContractDeploySend = Web3PromiEvent< + // eslint-disable-next-line no-use-before-define + Contract, + SendTransactionEvents +>; + +/* + * This class is only supposed to be used for the return of `new Contract(...).deploy(...)` method. + */ +export class DeployerMethodClass { + + protected readonly args: never[] | ContractConstructorArgs; + protected readonly constructorAbi: AbiConstructorFragment; + protected readonly contractOptions: ContractOptions; + protected readonly deployData?: string; + + protected _contractMethodDeploySend( + tx: TransactionCall, + ) { + // eslint-disable-next-line no-use-before-define + const returnTxOptions: SendTransactionOptions> = { + transactionResolver: (receipt: TransactionReceipt) => { + if (receipt.status === BigInt(0)) { + throw new Web3ContractError("code couldn't be stored", receipt); + } + + const newContract = this.parent.clone(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + newContract.options.address = receipt.contractAddress; + return newContract; + }, + + contractAbi: this.parent.options.jsonInterface, + // TODO Should make this configurable by the user + checkRevertBeforeSending: false, + }; + + return isNullish(this.parent.getTransactionMiddleware()) + ? sendTransaction(this.parent, tx, this.parent.defaultReturnFormat, returnTxOptions) // not calling this with undefined Middleware because it will not break if Eth package is not updated + : sendTransaction( + this.parent, + tx, + this.parent.defaultReturnFormat, + returnTxOptions, + this.parent.getTransactionMiddleware(), + ); + } + + public constructor( + // eslint-disable-next-line no-use-before-define + public parent: Contract, + public deployOptions: + | { + /** + * The byte code of the contract. + */ + data?: HexString; + input?: HexString; + /** + * The arguments which get passed to the constructor on deployment. + */ + arguments?: ContractConstructorArgs; + } + | undefined, + ) { + + const { args, abi, contractOptions, deployData} = this.calculateDeployParams(); + + this.args = args; + this.constructorAbi = abi; + this.contractOptions = contractOptions; + this.deployData = deployData; + } + + public send(options?: PayableTxOptions): ContractDeploySend { + const modifiedOptions = { ...options }; + + const tx = this.populateTransaction(modifiedOptions); + + return this._contractMethodDeploySend(tx); + } + + public populateTransaction( + txOptions?: PayableTxOptions | NonPayableTxOptions, + ) { + const modifiedContractOptions = { + ...this.contractOptions, + from: this.contractOptions.from ?? this.parent.defaultAccount ?? undefined, + }; + + // args, abi, contractOptions, deployData + + const tx = getSendTxParams({ + abi: this.constructorAbi, + params: this.args as unknown[], + options: { ...txOptions, dataInputFill: this.parent.contractDataInputFill }, + contractOptions: modifiedContractOptions, + }); + + // @ts-expect-error remove unnecessary field + if (tx.dataInputFill) { + // @ts-expect-error remove unnecessary field + delete tx.dataInputFill; + } + return tx; + } + + protected calculateDeployParams() { + let abi = this.parent.options.jsonInterface.find( + j => j.type === 'constructor', + ) as AbiConstructorFragment; + if (!abi) { + abi = { + type: 'constructor', + stateMutability: '', + } as AbiConstructorFragment; + } + + const _input = format( + { format: 'bytes' }, + this.deployOptions?.input ?? this.parent.options.input, + DEFAULT_RETURN_FORMAT, + ); + + const _data = format( + { format: 'bytes' }, + this.deployOptions?.data ?? this.parent.options.data, + DEFAULT_RETURN_FORMAT, + ); + + if ((!_input || _input.trim() === '0x') && (!_data || _data.trim() === '0x')) { + throw new Web3ContractError('contract creation without any data provided.'); + } + + const args = this.deployOptions?.arguments ?? []; + + const contractOptions: ContractOptions = { + ...this.parent.options, + input: _input, + data: _data, + }; + const deployData = _input ?? _data; + + return { args, abi, contractOptions, deployData} + } + + public async estimateGas( + options?: PayableCallOptions, + returnFormat: ReturnFormat = this.parent.defaultReturnFormat as ReturnFormat, + ) { + const modifiedOptions = { ...options }; + return this.parent.contractMethodEstimateGas({ + abi: this.constructorAbi as AbiFunctionFragment, + params: this.args as unknown[], + returnFormat, + options: modifiedOptions, + contractOptions: this.contractOptions, + }); + } + + public encodeABI() { + return encodeMethodABI( + this.constructorAbi, + this.args as unknown[], + format( + { format: 'bytes' }, + this.deployData as Bytes, + this.parent.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, + ), + ); + } + + public decodeData(data: HexString) { + return { + ...decodeMethodParams(this.constructorAbi, data.replace(this.deployData as string, ''), false), + __method__: this.constructorAbi.type, + }; + } +}; diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 09702a84a10..2528226ecc2 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -15,8 +15,6 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -/* eslint-disable max-classes-per-file */ - import { Web3Context, Web3EventEmitter, @@ -42,7 +40,6 @@ import { ALL_EVENTS_ABI, SendTransactionEvents, TransactionMiddleware, - SendTransactionOptions, } from 'web3-eth'; import { encodeEventSignature, @@ -54,7 +51,6 @@ import { jsonInterfaceMethodToString, } from 'web3-eth-abi'; import { - AbiConstructorFragment, AbiErrorFragment, AbiEventFragment, AbiFragment, @@ -69,7 +65,6 @@ import { Address, BlockNumberOrTag, BlockTags, - Bytes, EthExecutionAPI, Filter, FilterAbis, @@ -89,7 +84,6 @@ import { TransactionReceipt, FormatType, DecodedParams, - TransactionCall, } from 'web3-types'; import { format, @@ -127,6 +121,7 @@ import { getSendTxParams, isWeb3ContractContext, } from './utils.js'; +import { DeployerMethodClass } from './contract-deployer-method-class.js'; type ContractBoundMethod< Abi extends AbiFunctionFragment, @@ -171,11 +166,6 @@ export type ContractMethodSend = Web3PromiEvent< FormatType, SendTransactionEvents >; -export type ContractDeploySend = Web3PromiEvent< - // eslint-disable-next-line no-use-before-define - Contract, - SendTransactionEvents ->; /** * @hidden @@ -219,180 +209,6 @@ const contractSubscriptions = { }; -/* - * This class is only supposed to be used for the return of `new Contract(...).deploy(...)` method. - */ -export class DeployerMethodClass { - - protected readonly args: never[] | ContractConstructorArgs; - protected readonly constructorAbi: AbiConstructorFragment; - protected readonly contractOptions: ContractOptions; - protected readonly deployData?: string; - - protected _contractMethodDeploySend( - tx: TransactionCall, - ) { - // eslint-disable-next-line no-use-before-define - const returnTxOptions: SendTransactionOptions> = { - transactionResolver: (receipt: TransactionReceipt) => { - if (receipt.status === BigInt(0)) { - throw new Web3ContractError("code couldn't be stored", receipt); - } - - const newContract = this.parent.clone(); - - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - newContract.options.address = receipt.contractAddress; - return newContract; - }, - - contractAbi: this.parent.options.jsonInterface, - // TODO Should make this configurable by the user - checkRevertBeforeSending: false, - }; - - return isNullish(this.parent.getTransactionMiddleware()) - ? sendTransaction(this.parent, tx, this.parent.defaultReturnFormat, returnTxOptions) // not calling this with undefined Middleware because it will not break if Eth package is not updated - : sendTransaction( - this.parent, - tx, - this.parent.defaultReturnFormat, - returnTxOptions, - this.parent.getTransactionMiddleware(), - ); - } - - public constructor( - // eslint-disable-next-line no-use-before-define - public parent: Contract, - public deployOptions: - | { - /** - * The byte code of the contract. - */ - data?: HexString; - input?: HexString; - /** - * The arguments which get passed to the constructor on deployment. - */ - arguments?: ContractConstructorArgs; - } - | undefined, - ) { - - const { args, abi, contractOptions, deployData} = this.calculateDeployParams(); - - this.args = args; - this.constructorAbi = abi; - this.contractOptions = contractOptions; - this.deployData = deployData; - } - - public send(options?: PayableTxOptions): ContractDeploySend { - const modifiedOptions = { ...options }; - - const tx = this.populateTransaction(modifiedOptions); - - return this._contractMethodDeploySend(tx); - } - - public populateTransaction( - txOptions?: PayableTxOptions | NonPayableTxOptions, - ) { - const modifiedContractOptions = { - ...this.contractOptions, - from: this.contractOptions.from ?? this.parent.defaultAccount ?? undefined, - }; - - // args, abi, contractOptions, deployData - - const tx = getSendTxParams({ - abi: this.constructorAbi, - params: this.args as unknown[], - options: { ...txOptions, dataInputFill: this.parent.contractDataInputFill }, - contractOptions: modifiedContractOptions, - }); - - // @ts-expect-error remove unnecessary field - if (tx.dataInputFill) { - // @ts-expect-error remove unnecessary field - delete tx.dataInputFill; - } - return tx; - } - - protected calculateDeployParams() { - let abi = this.parent.options.jsonInterface.find( - j => j.type === 'constructor', - ) as AbiConstructorFragment; - if (!abi) { - abi = { - type: 'constructor', - stateMutability: '', - } as AbiConstructorFragment; - } - - const _input = format( - { format: 'bytes' }, - this.deployOptions?.input ?? this.parent.options.input, - DEFAULT_RETURN_FORMAT, - ); - - const _data = format( - { format: 'bytes' }, - this.deployOptions?.data ?? this.parent.options.data, - DEFAULT_RETURN_FORMAT, - ); - - if ((!_input || _input.trim() === '0x') && (!_data || _data.trim() === '0x')) { - throw new Web3ContractError('contract creation without any data provided.'); - } - - const args = this.deployOptions?.arguments ?? []; - - const contractOptions: ContractOptions = { - ...this.parent.options, - input: _input, - data: _data, - }; - const deployData = _input ?? _data; - - return { args, abi, contractOptions, deployData} - } - - public async estimateGas( - options?: PayableCallOptions, - returnFormat: ReturnFormat = this.parent.defaultReturnFormat as ReturnFormat, - ) { - const modifiedOptions = { ...options }; - return this.parent.contractMethodEstimateGas({ - abi: this.constructorAbi as AbiFunctionFragment, - params: this.args as unknown[], - returnFormat, - options: modifiedOptions, - contractOptions: this.contractOptions, - }); - } - - public encodeABI() { - return encodeMethodABI( - this.constructorAbi, - this.args as unknown[], - format( - { format: 'bytes' }, - this.deployData as Bytes, - this.parent.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, - ), - ); - } - - public decodeData(data: HexString) { - return { - ...decodeMethodParams(this.constructorAbi, data.replace(this.deployData as string, ''), false), - __method__: this.constructorAbi.type, - }; - } -}; /** * The `web3.eth.Contract` makes it easy to interact with smart contracts on the ethereum blockchain. diff --git a/packages/web3-eth-contract/src/index.ts b/packages/web3-eth-contract/src/index.ts index 09052f859a1..ad7b5ab7fb7 100644 --- a/packages/web3-eth-contract/src/index.ts +++ b/packages/web3-eth-contract/src/index.ts @@ -45,6 +45,7 @@ import { Contract } from './contract.js'; export * from './encoding.js'; export * from './contract.js'; +export * from './contract-deployer-method-class.js'; export * from './log_subscription.js'; export * from './types.js'; export * from './utils.js'; From 1b07f3592ff15c7dfeebbe9725e4837d2a253e41 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:16:02 +0200 Subject: [PATCH 10/13] disable import/no-cycle linting rule --- .../web3-eth-contract/src/contract-deployer-method-class.ts | 3 ++- packages/web3-eth-contract/src/contract.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth-contract/src/contract-deployer-method-class.ts b/packages/web3-eth-contract/src/contract-deployer-method-class.ts index 751d50d1113..e1acea18b6a 100644 --- a/packages/web3-eth-contract/src/contract-deployer-method-class.ts +++ b/packages/web3-eth-contract/src/contract-deployer-method-class.ts @@ -55,6 +55,7 @@ import { import { getSendTxParams, } from './utils.js'; +// eslint-disable-next-line import/no-cycle import { Contract } from './contract.js'; export type ContractDeploySend = Web3PromiEvent< @@ -225,7 +226,7 @@ export class DeployerMethodClass { format( { format: 'bytes' }, this.deployData as Bytes, - this.parent.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, + this.parent.defaultReturnFormat, ), ); } diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 2528226ecc2..910b348b55e 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -121,6 +121,7 @@ import { getSendTxParams, isWeb3ContractContext, } from './utils.js'; +// eslint-disable-next-line import/no-cycle import { DeployerMethodClass } from './contract-deployer-method-class.js'; type ContractBoundMethod< @@ -1259,7 +1260,7 @@ export class Contract this, tx, block, - this.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, + this.defaultReturnFormat , ); return decodeMethodReturn(abi, result); } catch (error: unknown) { From ad8e38d354824003886296461940308947ec8a00 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:19:22 +0200 Subject: [PATCH 11/13] tiny fix by adding a casting --- .../web3-eth-contract/src/contract-deployer-method-class.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth-contract/src/contract-deployer-method-class.ts b/packages/web3-eth-contract/src/contract-deployer-method-class.ts index e1acea18b6a..d57f7ae05b2 100644 --- a/packages/web3-eth-contract/src/contract-deployer-method-class.ts +++ b/packages/web3-eth-contract/src/contract-deployer-method-class.ts @@ -226,7 +226,7 @@ export class DeployerMethodClass { format( { format: 'bytes' }, this.deployData as Bytes, - this.parent.defaultReturnFormat, + this.parent.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, ), ); } From 3500003bbb4080545185511515accce2cebb5dd6 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:24:46 +0200 Subject: [PATCH 12/13] tiny fix by adding a casting --- packages/web3-eth-contract/src/contract.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 910b348b55e..2528226ecc2 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -121,7 +121,6 @@ import { getSendTxParams, isWeb3ContractContext, } from './utils.js'; -// eslint-disable-next-line import/no-cycle import { DeployerMethodClass } from './contract-deployer-method-class.js'; type ContractBoundMethod< @@ -1260,7 +1259,7 @@ export class Contract this, tx, block, - this.defaultReturnFormat , + this.defaultReturnFormat as typeof DEFAULT_RETURN_FORMAT, ); return decodeMethodReturn(abi, result); } catch (error: unknown) { From 744c62e78b971459b6a2d1b903682c9f40a4c61a Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:32:42 +0200 Subject: [PATCH 13/13] disable import/no-cycle linting rule --- packages/web3-eth-contract/src/contract.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 2528226ecc2..906cd3c8794 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -121,6 +121,7 @@ import { getSendTxParams, isWeb3ContractContext, } from './utils.js'; +// eslint-disable-next-line import/no-cycle import { DeployerMethodClass } from './contract-deployer-method-class.js'; type ContractBoundMethod<