Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions packages/web3-core/src/web3_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface Web3ConfigOptions {
transactionConfirmationPollingInterval?: number;
blockHeaderTimeout: number;
maxListenersWarningThreshold: number;
contractDataInputFill: 'data' | 'input' | 'both'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@luu-alex This config is specific for contract package only, so imo should be in contract package only instead of in web3_config class.

Copy link
Contributor Author

@luu-alex luu-alex Sep 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting it in web3_config class will allow users to only create this option once for all new contracts instantiated. If this was only in the contracts package, users with multiple contracts will need to define this option for every contract instance

defaultNetworkId?: Numbers;
defaultChain: string;
defaultHardfork: string;
Expand Down Expand Up @@ -78,6 +79,7 @@ export abstract class Web3Config
transactionConfirmationPollingInterval: undefined,
blockHeaderTimeout: 10,
maxListenersWarningThreshold: 100,
contractDataInputFill: 'input',
defaultNetworkId: undefined,
defaultChain: 'mainnet',
defaultHardfork: 'london',
Expand Down Expand Up @@ -126,6 +128,25 @@ export abstract class Web3Config
this.config.handleRevert = val;
}

/**
* The `contractDataInputFill` options property will allow you to set the hash of the method signature and encoded parameters to the property either `data`, `input` or both within your contract. This will affect:
* - myContract.deploy()
* - myContract.methods.myMethod().call()
* - myContract.methods.myMethod().send()
* Default is `input`.
*/
public get contractDataInputFill() {
return this.config.contractDataInputFill;
}

/**
* Will set the contractDataInputFill
*/
public set contractDataInputFill(val) {
this._triggerConfigChange('contractDataInputFill', val);
this.config.contractDataInputFill = val;
}

/**
* This default address is used as the default `from` property, if no `from` property is specified in for the following methods:
* - web3.eth.sendTransaction()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Object {
"accountProvider": undefined,
"config": Object {
"blockHeaderTimeout": 10,
"contractDataInputFill": "input",
"defaultAccount": undefined,
"defaultBlock": "latest",
"defaultChain": "mainnet",
Expand Down
1 change: 1 addition & 0 deletions packages/web3-core/test/unit/web3_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const defaultConfig = {
useRpcCallSpecification: false,
},
handleRevert: false,
contractDataInputFill: 'input',
maxListenersWarningThreshold: 100,
transactionBlockTimeout: 50,
transactionConfirmationBlocks: 24,
Expand Down
7 changes: 7 additions & 0 deletions packages/web3-eth-contract/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,10 @@ Documentation:
- In case of error events there will be inner error also available for details

## [Unreleased]

### Fixed

### Added

- Added `dataInputFill` as a ContractInitOption, allowing users to have the choice using property `data`, `input` or `both` for contract methods to be sent to the RPC provider. (#6355)
- Added to `Web3Config` property `contractDataInputFill` allowing users to have the choice using property `data`, `input` or `both` for contract methods to be sent to the RPC provider when creating contracts. (#6377)
73 changes: 44 additions & 29 deletions packages/web3-eth-contract/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export class Contract<Abi extends ContractAbi>
* myContract.options.gas = 5000000; // provide as fallback always 5M gas
* ```
*/

public readonly options: ContractOptions;

/**
Expand All @@ -233,6 +234,7 @@ export class Contract<Abi extends ContractAbi>
private readonly _overloadedMethodAbis: Map<string, AbiFunctionFragment[]>;
private _methods!: ContractMethodsInterface<Abi>;
private _events!: ContractEventsInterface<Abi>;
private readonly _dataInputFill?: 'data' | 'input' | 'both';

private context?: Web3Context;
/**
Expand Down Expand Up @@ -308,12 +310,6 @@ export class Contract<Abi extends ContractAbi>
? optionsOrContextOrReturnFormat
: undefined;

if (!isNullish(options) && !isNullish(options.data) && !isNullish(options.input))
throw new ContractTransactionDataAndInputError({
data: options.data as HexString,
input: options.input as HexString,
});

let contractContext;
if (isWeb3ContractContext(addressOrOptionsOrContext)) {
contractContext = addressOrOptionsOrContext;
Expand Down Expand Up @@ -348,7 +344,16 @@ export class Contract<Abi extends ContractAbi>
provider,
registeredSubscriptions: contractSubscriptions,
});

if (
!isNullish(options) &&
!isNullish(options.data) &&
!isNullish(options.input) &&
this.config.contractDataInputFill !== 'both'
)
throw new ContractTransactionDataAndInputError({
data: options.data as HexString,
input: options.input as HexString,
});
this._overloadedMethodAbis = new Map<string, AbiFunctionFragment[]>();

// eslint-disable-next-line no-nested-ternary
Expand All @@ -361,6 +366,13 @@ export class Contract<Abi extends ContractAbi>
const address =
typeof addressOrOptionsOrContext === 'string' ? addressOrOptionsOrContext : undefined;

if (this.config.contractDataInputFill === 'both') {
this._dataInputFill = this.config.contractDataInputFill;
} else {
this._dataInputFill =
(options as ContractInitOptions)?.dataInputFill ??
this.config.contractDataInputFill;
}
this._parseAndSetJsonInterface(jsonInterface, returnDataFormat);

if (!isNullish(address)) {
Expand All @@ -373,14 +385,14 @@ export class Contract<Abi extends ContractAbi>
gas: options?.gas ?? options?.gasLimit,
gasPrice: options?.gasPrice,
from: options?.from,
input: options?.input ?? options?.data,
input: options?.input,
data: options?.data,
};

this.syncWithContext = (options as ContractInitOptions)?.syncWithContext ?? false;
if (contractContext instanceof Web3Context) {
this.subscribeToContextEvents(contractContext);
}

Object.defineProperty(this.options, 'address', {
set: (value: Address) => this._parseAndSetAddress(value, returnDataFormat),
get: () => this._address,
Expand Down Expand Up @@ -470,7 +482,6 @@ export class Contract<Abi extends ContractAbi>
*/
public clone() {
let newContract: Contract<any>;

if (this.options.address) {
newContract = new Contract<Abi>(
[...this._jsonInterface, ...this._errorsInterface] as unknown as Abi,
Expand All @@ -480,8 +491,10 @@ export class Contract<Abi extends ContractAbi>
gasPrice: this.options.gasPrice,
from: this.options.from,
input: this.options.input,
data: this.options.data,
provider: this.currentProvider,
syncWithContext: this.syncWithContext,
dataInputFill: this._dataInputFill,
},
this.getContextObject(),
);
Expand All @@ -493,8 +506,10 @@ export class Contract<Abi extends ContractAbi>
gasPrice: this.options.gasPrice,
from: this.options.from,
input: this.options.input,
data: this.options.data,
provider: this.currentProvider,
syncWithContext: this.syncWithContext,
dataInputFill: this._dataInputFill,
},
this.getContextObject(),
);
Expand Down Expand Up @@ -577,7 +592,6 @@ export class Contract<Abi extends ContractAbi>
arguments?: ContractConstructorArgs<Abi>;
}) {
let abi = this._jsonInterface.find(j => j.type === 'constructor') as AbiConstructorFragment;

if (!abi) {
abi = {
type: 'constructor',
Expand All @@ -588,18 +602,24 @@ export class Contract<Abi extends ContractAbi>

const _input = format(
{ format: 'bytes' },
deployOptions?.input ?? deployOptions?.data ?? this.options.input,
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') {
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 };

const contractOptions: ContractOptions = { ...this.options, input: _input, data: _data };
const deployData = _input ?? _data;
return {
arguments: args,
send: (
Expand All @@ -623,7 +643,6 @@ export class Contract<Abi extends ContractAbi>
returnFormat: ReturnFormat = DEFAULT_RETURN_FORMAT as ReturnFormat,
) => {
const modifiedOptions = { ...options };

return this._contractMethodEstimateGas({
abi: abi as AbiFunctionFragment,
params: args as unknown[],
Expand All @@ -636,7 +655,7 @@ export class Contract<Abi extends ContractAbi>
encodeMethodABI(
abi as AbiFunctionFragment,
args as unknown[],
format({ format: 'bytes' }, _input as Bytes, DEFAULT_RETURN_FORMAT),
format({ format: 'bytes' }, deployData as Bytes, DEFAULT_RETURN_FORMAT),
),
};
}
Expand Down Expand Up @@ -783,7 +802,6 @@ export class Contract<Abi extends ContractAbi>
returnFormat: DataFormat = DEFAULT_RETURN_FORMAT,
) {
this._functions = {};

this._methods = {} as ContractMethodsInterface<Abi>;
this._events = {} as ContractEventsInterface<Abi>;

Expand Down Expand Up @@ -913,7 +931,6 @@ export class Contract<Abi extends ContractAbi>
throw new Web3ValidatorError(errors);
}
}

const methods = {
arguments: abiParams,

Expand Down Expand Up @@ -981,7 +998,10 @@ export class Contract<Abi extends ContractAbi>
const tx = getEthTxCallParams({
abi,
params,
options,
options: {
...options,
dataInputFill: this._dataInputFill,
},
contractOptions: {
...this.options,
from: this.options.from ?? this.config.defaultAccount,
Expand Down Expand Up @@ -1011,7 +1031,7 @@ export class Contract<Abi extends ContractAbi>
const tx = getCreateAccessListParams({
abi,
params,
options,
options: { ...options, dataInputFill: this.config.contractDataInputFill },
contractOptions: {
...this.options,
from: this.options.from ?? this.config.defaultAccount,
Expand Down Expand Up @@ -1042,11 +1062,10 @@ export class Contract<Abi extends ContractAbi>
input: undefined,
from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined,
};

const tx = getSendTxParams({
abi,
params,
options,
options: { ...options, dataInputFill: this.config.contractDataInputFill },
contractOptions: modifiedContractOptions,
});
const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, {
Expand All @@ -1061,7 +1080,6 @@ export class Contract<Abi extends ContractAbi>
decodeContractErrorData(errorsAbi, error.innerError);
}
});

return transactionToSend;
}

Expand All @@ -1076,14 +1094,12 @@ export class Contract<Abi extends ContractAbi>
...modifiedContractOptions,
from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined,
};

const tx = getSendTxParams({
abi,
params,
options,
options: { ...options, dataInputFill: this.config.contractDataInputFill },
contractOptions: modifiedContractOptions,
});

return sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, {
transactionResolver: receipt => {
if (receipt.status === BigInt(0)) {
Expand Down Expand Up @@ -1120,10 +1136,9 @@ export class Contract<Abi extends ContractAbi>
const tx = getEstimateGasParams({
abi,
params,
options,
options: { ...options, dataInputFill: this.config.contractDataInputFill },
contractOptions: contractOptions ?? this.options,
});

return estimateGas(this, tx, BlockTags.LATEST, returnFormat);
}

Expand Down
1 change: 0 additions & 1 deletion packages/web3-eth-contract/src/encoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ export const encodeMethodABI = (
deployData?: HexString,
) => {
const inputLength = Array.isArray(abi.inputs) ? abi.inputs.length : 0;

if (inputLength !== args.length) {
throw new Web3ContractError(
`The number of arguments is not matching the methods required number. You need to pass ${inputLength} arguments.`,
Expand Down
4 changes: 4 additions & 0 deletions packages/web3-eth-contract/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ export interface ContractOptions {
* The byte code of the contract. Used when the contract gets {@link Contract.deploy | deployed}
*/
readonly input?: Bytes;
/**
* The byte code of the contract. Used when the contract gets {@link Contract.deploy | deployed}
*/
readonly data?: Bytes;
/**
* The {@doclink glossary/json_interface | json interface} object derived from the [ABI](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) of this contract.
*
Expand Down
Loading