Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6355 - allow data to be used in contract methods. #6377

Merged
merged 33 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 20 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
29 changes: 16 additions & 13 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 Down Expand Up @@ -373,7 +374,8 @@ 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;
Expand Down Expand Up @@ -480,6 +482,7 @@ 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,
},
Expand All @@ -493,6 +496,7 @@ 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,
},
Expand Down Expand Up @@ -588,18 +592,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,
);

if (!_input || _input.trim() === '0x') {
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 };

const contractOptions: ContractOptions = { ...this.options, input: _input, data: _data };
const deployData = _input ?? _data;
return {
arguments: args,
send: (
Expand All @@ -623,7 +633,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 +645,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 @@ -913,7 +922,6 @@ export class Contract<Abi extends ContractAbi>
throw new Web3ValidatorError(errors);
}
}

const methods = {
arguments: abiParams,

Expand Down Expand Up @@ -1042,7 +1050,6 @@ export class Contract<Abi extends ContractAbi>
input: undefined,
from: modifiedContractOptions.from ?? this.defaultAccount ?? undefined,
};

const tx = getSendTxParams({
abi,
params,
Expand All @@ -1061,7 +1068,6 @@ export class Contract<Abi extends ContractAbi>
decodeContractErrorData(errorsAbi, error.innerError);
}
});

return transactionToSend;
}

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

const tx = getSendTxParams({
abi,
params,
options,
contractOptions: modifiedContractOptions,
});

return sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, {
transactionResolver: receipt => {
if (receipt.status === BigInt(0)) {
Expand Down Expand Up @@ -1123,7 +1127,6 @@ export class Contract<Abi extends ContractAbi>
options,
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
69 changes: 53 additions & 16 deletions packages/web3-eth-contract/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,32 @@ import { isNullish, mergeDeep, toHex } from 'web3-utils';
import { encodeMethodABI } from './encoding.js';
import { ContractOptions, Web3ContractContext } from './types.js';

const dataInputEncodeMethodHelper = (
txParams: TransactionCall,
abi: AbiFunctionFragment,
params: unknown[],
): TransactionCall => {
let tx = txParams;
if (tx.input) {
tx = {
...txParams,
input: encodeMethodABI(abi, params, txParams.input as HexString),
};
} else if (tx.data) {
tx = {
...txParams,
data: encodeMethodABI(abi, params, txParams.data as HexString),
};
} else {
// default to using input
tx = {
...txParams,
input: encodeMethodABI(abi, params, txParams.input as HexString),
};
}
return tx;
};

export const getSendTxParams = ({
abi,
params,
Expand All @@ -46,16 +72,15 @@ export const getSendTxParams = ({
};
contractOptions: ContractOptions;
}): TransactionCall => {
const deploymentCall = options?.input ?? options?.data ?? contractOptions.input;

const deploymentCall =
options?.input ?? options?.data ?? contractOptions.input ?? contractOptions.data;
if (!deploymentCall && !options?.to && !contractOptions.address) {
throw new Web3ContractError('Contract address not specified');
}

if (!options?.from && !contractOptions.from) {
throw new Web3ContractError('Contract "from" address not specified');
}

let txParams = mergeDeep(
{
to: contractOptions.address,
Expand All @@ -65,17 +90,11 @@ export const getSendTxParams = ({
input: contractOptions.input,
maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas,
maxFeePerGas: contractOptions.maxFeePerGas,
data: contractOptions.data,
},
options as unknown as Record<string, unknown>,
) as unknown as TransactionCall;

if (!txParams.input || abi.type === 'constructor') {
txParams = {
...txParams,
input: encodeMethodABI(abi, params, txParams.input as HexString),
};
}

txParams = dataInputEncodeMethodHelper(txParams, abi, params);
return txParams;
};

Expand Down Expand Up @@ -103,13 +122,15 @@ export const getEthTxCallParams = ({
input: contractOptions.input,
maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas,
maxFeePerGas: contractOptions.maxFeePerGas,
data: contractOptions.data,
},
options as unknown as Record<string, unknown>,
) as unknown as TransactionCall;

txParams = {
...txParams,
input: encodeMethodABI(abi, params, txParams.input ? toHex(txParams.input) : undefined),
data: encodeMethodABI(abi, params, txParams.data ? toHex(txParams.data) : undefined),
};

return txParams;
Expand All @@ -133,14 +154,19 @@ export const getEstimateGasParams = ({
gasPrice: contractOptions.gasPrice,
from: contractOptions.from,
input: contractOptions.input,
data: contractOptions.data,
},
options as unknown as Record<string, unknown>,
) as unknown as TransactionCall;

txParams = {
...txParams,
input: encodeMethodABI(abi, params, txParams.input ? toHex(txParams.input) : undefined),
};
if (txParams.input) {
txParams.input = toHex(txParams.input);
}
if (txParams.data) {
txParams.data = toHex(txParams.data);
}

txParams = dataInputEncodeMethodHelper(txParams, abi, params);

return txParams as TransactionWithSenderAPI;
};
Expand Down Expand Up @@ -191,11 +217,22 @@ export const getCreateAccessListParams = ({
input: contractOptions.input,
maxPriorityFeePerGas: contractOptions.maxPriorityFeePerGas,
maxFeePerGas: contractOptions.maxFeePerGas,
data: contractOptions.data,
},
options as unknown as Record<string, unknown>,
) as unknown as TransactionForAccessList;

if (!txParams.input || abi.type === 'constructor') {
if (txParams.input) {
txParams = {
...txParams,
input: encodeMethodABI(abi, params, txParams.input as HexString),
};
} else if (txParams.data) {
txParams = {
...txParams,
data: encodeMethodABI(abi, params, txParams.data as HexString),
};
} else {
txParams = {
...txParams,
input: encodeMethodABI(abi, params, txParams.input as HexString),
Expand Down
Loading