diff --git a/CHANGELOG.md b/CHANGELOG.md
index 59eb701334b..98da596e4a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2007,7 +2007,6 @@ If there are any bugs, improvements, optimizations or any new feature proposal f
#### web3-eth-contract
-
#### web3-utils
- `soliditySha3()` with BigInt support
@@ -2021,6 +2020,7 @@ If there are any bugs, improvements, optimizations or any new feature proposal f
#### web3-eth
- 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) (#6400)
+- Added `ALL_EVENTS` and `ALL_EVENTS_ABI` constants, `SendTransactionEventsBase` type, `decodeEventABI` method (#6410)
#### web3-eth-contract
@@ -2081,5 +2081,26 @@ If there are any bugs, improvements, optimizations or any new feature proposal f
- Dependencies updated
-
## [Unreleased]
+
+### Added
+
+#### web3-eth
+
+- Added `ALL_EVENTS` and `ALL_EVENTS_ABI` constants, `SendTransactionEventsBase` type, `decodeEventABI` method (#6410)
+
+#### web3-types
+
+- Interface `EventLog` was added. (#6410)
+
+### Fixed
+
+#### web3-eth
+
+- Ensure provider.supportsSubscriptions exists before watching by subscription (#6440)
+
+### Changed
+
+#### web3-eth-contract
+
+- The `events` property was added to the `receipt` object (#6410)
diff --git a/packages/web3-eth-abi/test/unit/get_encoded_eip712_data.test.ts b/packages/web3-eth-abi/test/unit/get_encoded_eip712_data.test.ts
index d40c5f25511..f20d725010f 100644
--- a/packages/web3-eth-abi/test/unit/get_encoded_eip712_data.test.ts
+++ b/packages/web3-eth-abi/test/unit/get_encoded_eip712_data.test.ts
@@ -24,6 +24,6 @@ describe('getEncodedEip712Data', () => {
});
it.each(erroneousTestData)('%s', (_, typedData, hashEncodedData, expectedError) => {
- expect(() => getEncodedEip712Data(typedData, hashEncodedData)).toThrowError(expectedError);
+ expect(() => getEncodedEip712Data(typedData, hashEncodedData)).toThrow(expectedError);
});
});
diff --git a/packages/web3-eth-contract/CHANGELOG.md b/packages/web3-eth-contract/CHANGELOG.md
index 4e1667e2a96..cd30b90db36 100644
--- a/packages/web3-eth-contract/CHANGELOG.md
+++ b/packages/web3-eth-contract/CHANGELOG.md
@@ -308,4 +308,8 @@ Documentation:
- 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)
-## [Unreleased]
\ No newline at end of file
+## [Unreleased]
+
+### Changed
+
+- The `events` property was added to the `receipt` object (#6410)
diff --git a/packages/web3-eth-contract/src/constants.ts b/packages/web3-eth-contract/src/constant.ts
similarity index 73%
rename from packages/web3-eth-contract/src/constants.ts
rename to packages/web3-eth-contract/src/constant.ts
index a0420e2534a..6be67ffb159 100644
--- a/packages/web3-eth-contract/src/constants.ts
+++ b/packages/web3-eth-contract/src/constant.ts
@@ -1,4 +1,4 @@
-/*
+/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
@@ -14,13 +14,4 @@ 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 { AbiEventFragment } from 'web3-types';
-
-export const ALL_EVENTS = 'ALLEVENTS';
-export const ALL_EVENTS_ABI = {
- name: ALL_EVENTS,
- signature: '',
- type: 'event',
- inputs: [],
-} as AbiEventFragment & { signature: string };
+export { ALL_EVENTS, ALL_EVENTS_ABI } from 'web3-eth';
diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts
index 01c757b3946..dcf726b07e5 100644
--- a/packages/web3-eth-contract/src/contract.ts
+++ b/packages/web3-eth-contract/src/contract.ts
@@ -33,8 +33,11 @@ import {
call,
estimateGas,
getLogs,
- NewHeadsSubscription,
sendTransaction,
+ decodeEventABI,
+ NewHeadsSubscription,
+ ALL_EVENTS,
+ ALL_EVENTS_ABI,
SendTransactionEvents,
} from 'web3-eth';
import {
@@ -76,6 +79,9 @@ import {
DEFAULT_RETURN_FORMAT,
Numbers,
Web3ValidationErrorObject,
+ EventLog,
+ ContractAbiWithSignature,
+ ContractOptions,
} from 'web3-types';
import { format, isDataFormat, keccak256, toChecksumAddress } from 'web3-utils';
import {
@@ -85,14 +91,10 @@ import {
ValidationSchemaInput,
Web3ValidatorError,
} from 'web3-validator';
-import { ALL_EVENTS, ALL_EVENTS_ABI } from './constants.js';
-import { decodeEventABI, decodeMethodReturn, encodeEventABI, encodeMethodABI } from './encoding.js';
+import { decodeMethodReturn, encodeEventABI, encodeMethodABI } from './encoding.js';
import { LogsSubscription } from './log_subscription.js';
import {
- ContractAbiWithSignature,
ContractEventOptions,
- ContractOptions,
- EventLog,
NonPayableMethodObject,
NonPayableTxOptions,
PayableMethodObject,
@@ -707,7 +709,7 @@ export class Contract
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents(
- eventName: keyof ContractEvents | 'allEvents',
+ eventName: keyof ContractEvents | 'allEvents' | 'ALLEVENTS',
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents(
@@ -715,16 +717,21 @@ export class Contract
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents(
- eventName: keyof ContractEvents | 'allEvents',
+ eventName: keyof ContractEvents | 'allEvents' | 'ALLEVENTS',
filter: Omit,
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents(
- param1?: keyof ContractEvents | 'allEvents' | Omit | ReturnFormat,
+ param1?:
+ | keyof ContractEvents
+ | 'allEvents'
+ | 'ALLEVENTS'
+ | Omit
+ | ReturnFormat,
param2?: Omit | ReturnFormat,
param3?: ReturnFormat,
): Promise<(string | EventLog)[]> {
- const eventName = typeof param1 === 'string' ? param1 : 'allEvents';
+ const eventName = typeof param1 === 'string' ? param1 : ALL_EVENTS;
const options =
// eslint-disable-next-line no-nested-ternary
@@ -751,11 +758,13 @@ export class Contract
if (!abi) {
throw new Web3ContractError(`Event ${eventName} not found.`);
}
+
const { fromBlock, toBlock, topics, address } = encodeEventABI(
this.options,
abi,
options ?? {},
);
+
const logs = await getLogs(this, { fromBlock, toBlock, topics, address }, returnFormat);
const decodedLogs = logs.map(log =>
typeof log === 'string'
@@ -1076,6 +1085,7 @@ export class Contract
const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, {
// TODO Should make this configurable by the user
checkRevertBeforeSending: false,
+ contractAbi: this._jsonInterface,
});
// eslint-disable-next-line no-void
@@ -1117,6 +1127,7 @@ export class Contract
newContract.options.address = receipt.contractAddress;
return newContract;
},
+ contractAbi: this._jsonInterface,
// TODO Should make this configurable by the user
checkRevertBeforeSending: false,
});
diff --git a/packages/web3-eth-contract/src/encoding.ts b/packages/web3-eth-contract/src/encoding.ts
index 0f79aac467e..aa06db45ae8 100644
--- a/packages/web3-eth-contract/src/encoding.ts
+++ b/packages/web3-eth-contract/src/encoding.ts
@@ -21,18 +21,15 @@ import {
AbiConstructorFragment,
AbiEventFragment,
AbiFunctionFragment,
- LogsInput,
Filter,
HexString,
Topic,
FMT_NUMBER,
FMT_BYTES,
- DataFormat,
- DEFAULT_RETURN_FORMAT,
+ ContractOptions,
} from 'web3-types';
import {
- decodeLog,
decodeParameters,
encodeEventSignature,
encodeFunctionSignature,
@@ -42,12 +39,10 @@ import {
jsonInterfaceMethodToString,
} from 'web3-eth-abi';
-import { blockSchema, logSchema } from 'web3-eth';
-
+import { blockSchema, ALL_EVENTS } from 'web3-eth';
import { Web3ContractError } from 'web3-errors';
-// eslint-disable-next-line import/no-cycle
-import { ContractOptions, ContractAbiWithSignature, EventLog } from './types.js';
+export { decodeEventABI } from 'web3-eth';
type Writeable = { -readonly [P in keyof T]: T[P] };
export const encodeEventABI = (
@@ -77,14 +72,14 @@ export const encodeEventABI = (
} else {
opts.topics = [];
// add event signature
- if (event && !event.anonymous && event.name !== 'ALLEVENTS') {
+ if (event && !event.anonymous && ![ALL_EVENTS, 'allEvents'].includes(event.name)) {
opts.topics.push(
event.signature ?? encodeEventSignature(jsonInterfaceMethodToString(event)),
);
}
// add event topics (indexed arguments)
- if (event.name !== 'ALLEVENTS' && event.inputs) {
+ if (![ALL_EVENTS, 'allEvents'].includes(event.name) && event.inputs) {
for (const input of event.inputs) {
if (!input.indexed) {
continue;
@@ -119,68 +114,6 @@ export const encodeEventABI = (
return opts;
};
-export const decodeEventABI = (
- event: AbiEventFragment & { signature: string },
- data: LogsInput,
- jsonInterface: ContractAbiWithSignature,
- returnFormat: DataFormat = DEFAULT_RETURN_FORMAT,
-): EventLog => {
- let modifiedEvent = { ...event };
-
- const result = format(logSchema, data, returnFormat);
-
- // if allEvents get the right event
- if (modifiedEvent.name === 'ALLEVENTS') {
- const matchedEvent = jsonInterface.find(j => j.signature === data.topics[0]);
- if (matchedEvent) {
- modifiedEvent = matchedEvent as AbiEventFragment & { signature: string };
- } else {
- modifiedEvent = { anonymous: true } as unknown as AbiEventFragment & {
- signature: string;
- };
- }
- }
-
- // create empty inputs if none are present (e.g. anonymous events on allEvents)
- modifiedEvent.inputs = modifiedEvent.inputs ?? event.inputs ?? [];
-
- // Handle case where an event signature shadows the current ABI with non-identical
- // arg indexing. If # of topics doesn't match, event is anon.
- if (!modifiedEvent.anonymous) {
- let indexedInputs = 0;
- (modifiedEvent.inputs ?? []).forEach(input => {
- if (input.indexed) {
- indexedInputs += 1;
- }
- });
-
- if (indexedInputs > 0 && data?.topics && data?.topics.length !== indexedInputs + 1) {
- // checks if event is anonymous
- modifiedEvent = {
- ...modifiedEvent,
- anonymous: true,
- inputs: [],
- };
- }
- }
-
- const argTopics = modifiedEvent.anonymous ? data.topics : (data.topics ?? []).slice(1);
- return {
- ...result,
- returnValues: decodeLog([...(modifiedEvent.inputs ?? [])], data.data, argTopics),
- event: modifiedEvent.name,
- signature:
- modifiedEvent.anonymous || !data.topics || data.topics.length === 0 || !data.topics[0]
- ? undefined
- : data.topics[0],
-
- raw: {
- data: data.data,
- topics: data.topics,
- },
- };
-};
-
export const encodeMethodABI = (
abi: AbiFunctionFragment | AbiConstructorFragment,
args: unknown[],
diff --git a/packages/web3-eth-contract/src/log_subscription.ts b/packages/web3-eth-contract/src/log_subscription.ts
index 48504e9a86f..6ace1e17478 100644
--- a/packages/web3-eth-contract/src/log_subscription.ts
+++ b/packages/web3-eth-contract/src/log_subscription.ts
@@ -15,12 +15,17 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
-import { AbiEventFragment, LogsInput, HexString, Topic, DataFormat } from 'web3-types';
+import {
+ AbiEventFragment,
+ LogsInput,
+ HexString,
+ Topic,
+ DataFormat,
+ EventLog,
+ ContractAbiWithSignature,
+} from 'web3-types';
import { Web3RequestManager, Web3Subscription, Web3SubscriptionManager } from 'web3-core';
-// eslint-disable-next-line import/no-cycle
-import { decodeEventABI } from './encoding.js';
-// eslint-disable-next-line import/no-cycle
-import { EventLog, ContractAbiWithSignature } from './types.js';
+import { decodeEventABI } from 'web3-eth';
/**
* LogSubscription to be used to subscribe to events logs.
diff --git a/packages/web3-eth-contract/src/types.ts b/packages/web3-eth-contract/src/types.ts
index 0b62afcc37c..fc66826b2e6 100644
--- a/packages/web3-eth-contract/src/types.ts
+++ b/packages/web3-eth-contract/src/types.ts
@@ -16,7 +16,6 @@ along with web3.js. If not, see .
*/
import { Web3ContextInitOptions, Web3PromiEvent } from 'web3-core';
-import { NewHeadsSubscription, SendTransactionEvents } from 'web3-eth';
import {
AccessListResult,
BlockNumberOrTag,
@@ -29,36 +28,13 @@ import {
DataFormat,
DEFAULT_RETURN_FORMAT,
FormatType,
- AbiFragment,
- Address,
- Bytes,
- ContractAbi,
- HexString32Bytes,
- Uint,
} from 'web3-types';
-// eslint-disable-next-line import/no-cycle
+import { NewHeadsSubscription, SendTransactionEvents } from 'web3-eth';
import { LogsSubscription } from './log_subscription.js';
export type NonPayableTxOptions = NonPayableCallOptions;
export type PayableTxOptions = PayableCallOptions;
-
-export type ContractAbiWithSignature = ReadonlyArray;
-
-export interface EventLog {
- readonly event: string;
- readonly id?: string;
- readonly logIndex?: bigint | number | string;
- readonly transactionIndex?: bigint | number | string;
- readonly transactionHash?: HexString32Bytes;
- readonly blockHash?: HexString32Bytes;
- readonly blockNumber?: bigint | number | string;
- readonly address: string;
- readonly topics: HexString[];
- readonly data: HexString;
- readonly raw?: { data: string; topics: unknown[] };
- readonly returnValues: Record;
- readonly signature?: HexString;
-}
+export { ContractAbiWithSignature, EventLog, ContractOptions } from 'web3-types';
export interface ContractEventOptions {
/**
@@ -75,80 +51,6 @@ export interface ContractEventOptions {
topics?: string[];
}
-export interface ContractOptions {
- /**
- * The maximum gas provided for a transaction (gas limit).
- */
- readonly gas?: Uint;
- /**
- * The gas price in wei to use for transactions.
- */
- readonly gasPrice?: Uint;
- /**
- * The address transactions should be made from.
- */
- readonly from?: Address;
- /**
- * 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.
- *
- * Re-setting this will regenerate the methods and events of the contract instance.
- *
- * ```ts
- * myContract.options.jsonInterface;
- * > [{
- * "type":"function",
- * "name":"foo",
- * "inputs": [{"name":"a","type":"uint256"}],
- * "outputs": [{"name":"b","type":"address"}],
- * "signature": "0x...",
- * },{
- * "type":"event",
- * "name":"Event",
- * "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}],
- * "signature": "0x...",
- * }]
- *
- * // Set a new ABI interface
- * // Note: the "signature" of every function and event's ABI is not needed to be provided when assigning.
- * // It will be calculated and set automatically inside the setter.
- * myContract.options.jsonInterface = [...];
- * ```
- */
- get jsonInterface(): ContractAbiWithSignature;
- set jsonInterface(value: ContractAbi);
-
- /**
- * The address used for this contract instance. All transactions generated by web3.js from this contract will contain this address as the `to`.
- *
- * The address will be stored in lowercase.
- *
- * ```ts
- * myContract.options.address;
- * > '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae'
- *
- * // set a new address
- * myContract.options.address = '0x1234FFDD...';
- * ```
- */
- address?: Address; // All transactions generated by web3.js from this contract will contain this address as the "to".
- /**
- * The max priority fee per gas to use for transactions.
- */
- maxPriorityFeePerGas?: Uint;
- /**
- * The max fee per gas to use for transactions.
- */
- maxFeePerGas?: Uint;
-}
-
export interface NonPayableMethodObject {
arguments: Inputs;
/**
diff --git a/packages/web3-eth-contract/src/utils.ts b/packages/web3-eth-contract/src/utils.ts
index ca3fd7f9c34..2cbe4a49715 100644
--- a/packages/web3-eth-contract/src/utils.ts
+++ b/packages/web3-eth-contract/src/utils.ts
@@ -26,10 +26,11 @@ import {
NonPayableCallOptions,
PayableCallOptions,
ContractInitOptions,
+ ContractOptions,
} from 'web3-types';
import { isNullish, mergeDeep } from 'web3-utils';
import { encodeMethodABI } from './encoding.js';
-import { ContractOptions, Web3ContractContext } from './types.js';
+import { Web3ContractContext } from './types.js';
const dataInputEncodeMethodHelper = (
txParams: TransactionCall | TransactionForAccessList,
diff --git a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts
index 5c6c666212c..0fbafac4d0f 100644
--- a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts
+++ b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts
@@ -40,7 +40,7 @@ describe('contract', () => {
let pkAccount: { address: string; privateKey: string };
let web3Eth: Web3Eth;
- beforeAll(async () => {
+ beforeAll(() => {
web3Eth = new Web3Eth(getSystemTestProvider());
deployOptions = {
data: GreeterBytecode,
diff --git a/packages/web3-eth-contract/test/integration/contract_erc20.test.ts b/packages/web3-eth-contract/test/integration/contract_erc20.test.ts
index 9c3c92a8043..15d1852a055 100644
--- a/packages/web3-eth-contract/test/integration/contract_erc20.test.ts
+++ b/packages/web3-eth-contract/test/integration/contract_erc20.test.ts
@@ -94,7 +94,27 @@ describe('contract', () => {
it('should transfer tokens', async () => {
const acc2 = await createTempAccount();
const value = BigInt(10);
- await contractDeployed.methods.transfer(acc2.address, value).send(sendOptions);
+ const receipt = await contractDeployed.methods
+ .transfer(acc2.address, value)
+ .send(sendOptions);
+
+ expect(receipt.events).toBeDefined();
+ expect(receipt.events?.Transfer).toBeDefined();
+ expect(receipt.events?.Transfer.event).toBe('Transfer');
+ expect(String(receipt.events?.Transfer.returnValues.from).toLowerCase()).toBe(
+ mainAcc.address.toLowerCase(),
+ );
+ expect(String(receipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ mainAcc.address.toLowerCase(),
+ );
+ expect(String(receipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ acc2.address.toLowerCase(),
+ );
+ expect(String(receipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ acc2.address.toLowerCase(),
+ );
+ expect(receipt.events?.Transfer.returnValues.value).toBe(value);
+ expect(receipt.events?.Transfer.returnValues[2]).toBe(value);
expect(await contractDeployed.methods.balanceOf(acc2.address).call()).toBe(
value,
diff --git a/packages/web3-eth-contract/test/integration/contract_erc721.test.ts b/packages/web3-eth-contract/test/integration/contract_erc721.test.ts
index 21c31e5e8cb..9463a636930 100644
--- a/packages/web3-eth-contract/test/integration/contract_erc721.test.ts
+++ b/packages/web3-eth-contract/test/integration/contract_erc721.test.ts
@@ -81,10 +81,25 @@ describe('contract', () => {
it('should award item', async () => {
const tempAccount = await createTempAccount();
- await contractDeployed.methods
+ const receipt = await contractDeployed.methods
.awardItem(tempAccount.address, 'http://my-nft-uri')
.send(sendOptions);
+ expect(receipt.events).toBeDefined();
+ expect(receipt.events?.Transfer).toBeDefined();
+ expect(receipt.events?.Transfer.event).toBe('Transfer');
+ expect(String(receipt.events?.Transfer.returnValues.from).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(receipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(receipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(String(receipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
const tokenId = toBigInt(0);
expect(
toUpperCaseHex(
@@ -289,9 +304,25 @@ describe('contract', () => {
});
});
- await contractDeployed.methods
+ const receipt = await contractDeployed.methods
.awardItem(acc2.address, 'http://my-nft-uri')
.send(sendOptions);
+
+ expect(receipt.events).toBeDefined();
+ expect(receipt.events?.Transfer).toBeDefined();
+ expect(receipt.events?.Transfer.event).toBe('Transfer');
+ expect(
+ String(receipt.events?.Transfer.returnValues.from).toLowerCase(),
+ ).toBe('0x0000000000000000000000000000000000000000');
+ expect(
+ String(receipt.events?.Transfer.returnValues[0]).toLowerCase(),
+ ).toBe('0x0000000000000000000000000000000000000000');
+ expect(
+ String(receipt.events?.Transfer.returnValues.to).toLowerCase(),
+ ).toBe(acc2.address.toLowerCase());
+ expect(
+ String(receipt.events?.Transfer.returnValues[1]).toLowerCase(),
+ ).toBe(acc2.address.toLowerCase());
}),
).resolves.toEqual({
from: '0x0000000000000000000000000000000000000000',
diff --git a/packages/web3-eth-contract/test/integration/contract_events.test.ts b/packages/web3-eth-contract/test/integration/contract_events.test.ts
index 0813e16f3f1..b84a875d173 100644
--- a/packages/web3-eth-contract/test/integration/contract_events.test.ts
+++ b/packages/web3-eth-contract/test/integration/contract_events.test.ts
@@ -15,7 +15,8 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
-import { Contract, EventLog } from '../../src';
+import { EventLog } from 'web3-types';
+import { Contract } from '../../src';
import { BasicAbi, BasicBytecode } from '../shared_fixtures/build/Basic';
import { processAsync } from '../shared_fixtures/utils';
import {
diff --git a/packages/web3-eth-contract/test/integration/contract_filter_events.test.ts b/packages/web3-eth-contract/test/integration/contract_filter_events.test.ts
index e0c26a3b453..338cd448c12 100644
--- a/packages/web3-eth-contract/test/integration/contract_filter_events.test.ts
+++ b/packages/web3-eth-contract/test/integration/contract_filter_events.test.ts
@@ -16,6 +16,7 @@ along with web3.js. If not, see .
*/
import { toBigInt } from 'web3-utils';
+import { EventLog } from 'web3-types';
import { Contract } from '../../src';
import { ERC20TokenAbi, ERC20TokenBytecode } from '../shared_fixtures/build/ERC20Token';
import { BasicAbi, BasicBytecode } from '../shared_fixtures/build/Basic';
@@ -24,7 +25,6 @@ import {
createTempAccount,
createNewAccount,
} from '../fixtures/system_test_utils';
-import { EventLog } from '../../src/types';
const initialSupply = BigInt('5000000000');
diff --git a/packages/web3-eth-contract/test/integration/contract_methods.test.ts b/packages/web3-eth-contract/test/integration/contract_methods.test.ts
index f63923cdfbe..7f072d5a358 100644
--- a/packages/web3-eth-contract/test/integration/contract_methods.test.ts
+++ b/packages/web3-eth-contract/test/integration/contract_methods.test.ts
@@ -92,6 +92,7 @@ describe('contract', () => {
.setValues(1, 'string value', true)
.send(sendOptions);
+ expect(receipt.events).toBeUndefined();
expect(receipt).toEqual(
expect.objectContaining({
// status: BigInt(1),
diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts
index bd379e5f647..edff03fe598 100644
--- a/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts
+++ b/packages/web3-eth-contract/test/integration/local_account/contract_erc20.test.ts
@@ -61,11 +61,30 @@ describe('contract', () => {
const acc = web3.eth.accounts.create();
const value = BigInt(10);
- await contractDeployed.methods.transfer(acc.address, value).send({
+ const receipt = await contractDeployed.methods.transfer(acc.address, value).send({
...sendOptions,
type,
});
-
+ expect(receipt.events).toBeDefined();
+ expect(receipt.events?.Transfer).toBeDefined();
+ expect(receipt.events?.Transfer.event).toBe('Transfer');
+ expect(receipt.events).toBeDefined();
+ expect(receipt.events?.Transfer).toBeDefined();
+ expect(receipt.events?.Transfer.event).toBe('Transfer');
+ expect(String(receipt.events?.Transfer.returnValues.from).toLowerCase()).toBe(
+ localAccount.address.toLowerCase(),
+ );
+ expect(String(receipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ localAccount.address.toLowerCase(),
+ );
+ expect(String(receipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ acc.address.toLowerCase(),
+ );
+ expect(String(receipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ acc.address.toLowerCase(),
+ );
+ expect(receipt.events?.Transfer.returnValues.value).toBe(value);
+ expect(receipt.events?.Transfer.returnValues[2]).toBe(value);
expect(await contractDeployed.methods.balanceOf(acc.address).call()).toBe(value);
});
@@ -74,14 +93,55 @@ describe('contract', () => {
const transferFromValue = BigInt(4);
const tempAccount = await createLocalAccount(web3);
// approve
- await contractDeployed.methods
+ const approvalReceipt = await contractDeployed.methods
.approve(tempAccount.address, value)
.send({ ...sendOptions, type });
-
+ expect(approvalReceipt.events).toBeDefined();
+ expect(approvalReceipt.events?.Approval).toBeDefined();
+ expect(approvalReceipt.events?.Approval.event).toBe('Approval');
// transferFrom
- await contractDeployed.methods
+ const transferFromReceipt = await contractDeployed.methods
.transferFrom(localAccount.address, tempAccount.address, transferFromValue)
.send({ ...sendOptions, from: tempAccount.address, type });
+ expect(transferFromReceipt.events).toBeDefined();
+ expect(transferFromReceipt.events?.Approval).toBeDefined();
+ expect(transferFromReceipt.events?.Approval.event).toBe('Approval');
+ expect(
+ String(transferFromReceipt.events?.Approval.returnValues.owner).toLowerCase(),
+ ).toBe(localAccount.address.toLowerCase());
+ expect(String(transferFromReceipt.events?.Approval.returnValues[0]).toLowerCase()).toBe(
+ localAccount.address.toLowerCase(),
+ );
+ expect(
+ String(transferFromReceipt.events?.Approval.returnValues.spender).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(String(transferFromReceipt.events?.Approval.returnValues[1]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(transferFromReceipt.events?.Approval.returnValues.value).toBe(
+ value - transferFromValue,
+ );
+ expect(transferFromReceipt.events?.Approval.returnValues[2]).toBe(
+ value - transferFromValue,
+ );
+
+ expect(transferFromReceipt.events?.Transfer).toBeDefined();
+ expect(transferFromReceipt.events?.Transfer.event).toBe('Transfer');
+ expect(transferFromReceipt.events).toBeDefined();
+ expect(
+ String(transferFromReceipt.events?.Transfer.returnValues.from).toLowerCase(),
+ ).toBe(localAccount.address.toLowerCase());
+ expect(String(transferFromReceipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ localAccount.address.toLowerCase(),
+ );
+ expect(String(transferFromReceipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(String(transferFromReceipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(transferFromReceipt.events?.Transfer.returnValues.value).toBe(transferFromValue);
+ expect(transferFromReceipt.events?.Transfer.returnValues[2]).toBe(transferFromValue);
expect(await contractDeployed.methods.balanceOf(tempAccount.address).call()).toBe(
transferFromValue,
@@ -101,9 +161,26 @@ describe('contract', () => {
const tempAccount = await createLocalAccount(web3);
// approve
- await contractDeployed.methods
+ const approvalReceipt = await contractDeployed.methods
.approve(tempAccount.address, value)
.send({ ...sendOptions, type });
+ expect(approvalReceipt.events).toBeDefined();
+ expect(approvalReceipt.events?.Approval).toBeDefined();
+ expect(approvalReceipt.events?.Approval.event).toBe('Approval');
+ expect(String(approvalReceipt.events?.Approval.returnValues.owner).toLowerCase()).toBe(
+ localAccount.address.toLowerCase(),
+ );
+ expect(String(approvalReceipt.events?.Approval.returnValues[0]).toLowerCase()).toBe(
+ localAccount.address.toLowerCase(),
+ );
+ expect(
+ String(approvalReceipt.events?.Approval.returnValues.spender).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(String(approvalReceipt.events?.Approval.returnValues[1]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(approvalReceipt.events?.Approval.returnValues.value).toBe(value);
+ expect(approvalReceipt.events?.Approval.returnValues[2]).toBe(value);
// allowance
expect(
@@ -113,10 +190,33 @@ describe('contract', () => {
).toBe(value);
// increaseAllowance
- await contractDeployed.methods
+ const increaseAllowanceReceipt = await contractDeployed.methods
.increaseAllowance(tempAccount.address, extraAmount)
.send({ ...sendOptions, from: localAccount.address, type, gas: '2000000' });
+ expect(increaseAllowanceReceipt.events).toBeDefined();
+ expect(increaseAllowanceReceipt.events?.Approval).toBeDefined();
+ expect(increaseAllowanceReceipt.events?.Approval.event).toBe('Approval');
+ expect(
+ String(increaseAllowanceReceipt.events?.Approval.returnValues.owner).toLowerCase(),
+ ).toBe(localAccount.address.toLowerCase());
+ expect(
+ String(increaseAllowanceReceipt.events?.Approval.returnValues[0]).toLowerCase(),
+ ).toBe(localAccount.address.toLowerCase());
+ expect(
+ String(
+ increaseAllowanceReceipt.events?.Approval.returnValues.spender,
+ ).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(increaseAllowanceReceipt.events?.Approval.returnValues[1]).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(increaseAllowanceReceipt.events?.Approval.returnValues.value).toBe(
+ value + extraAmount,
+ );
+ expect(increaseAllowanceReceipt.events?.Approval.returnValues[2]).toBe(
+ value + extraAmount,
+ );
// check allowance
expect(
await contractDeployed.methods
diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_erc721.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_erc721.test.ts
index b9ad5b2ac0d..2b50e735257 100644
--- a/packages/web3-eth-contract/test/integration/local_account/contract_erc721.test.ts
+++ b/packages/web3-eth-contract/test/integration/local_account/contract_erc721.test.ts
@@ -19,7 +19,8 @@ along with web3.js. If not, see .
import Web3 from 'web3';
// eslint-disable-next-line import/no-extraneous-dependencies
import { Web3Account } from 'web3-eth-accounts';
-import { Contract, EventLog } from '../../../src';
+import { EventLog } from 'web3-types';
+import { Contract } from '../../../src';
import { ERC721TokenAbi, ERC721TokenBytecode } from '../../shared_fixtures/build/ERC721Token';
import { getSystemTestProvider, createLocalAccount } from '../../fixtures/system_test_utils';
import { toUpperCaseHex } from '../../shared_fixtures/utils';
@@ -59,9 +60,25 @@ describe('contract', () => {
it.each(['0x1', '0x2'])('should award item %p', async type => {
const tempAccount = web3.eth.accounts.create();
- await contractDeployed.methods
+ const awardReceipt = await contractDeployed.methods
.awardItem(tempAccount.address, 'http://my-nft-uri')
.send({ ...sendOptions, type });
+ expect(awardReceipt.events).toBeDefined();
+ expect(awardReceipt.events?.Transfer).toBeDefined();
+ expect(awardReceipt.events?.Transfer.event).toBe('Transfer');
+
+ expect(String(awardReceipt.events?.Transfer.returnValues.from).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
const logs = await contractDeployed.getPastEvents('Transfer');
const tokenId = (logs[0] as EventLog)?.returnValues?.tokenId as string;
@@ -76,19 +93,69 @@ describe('contract', () => {
it.each(['0x1', '0x2'])('should transferFrom item %p', async type => {
const tempAccount = await createLocalAccount(web3);
const toAccount = await createLocalAccount(web3);
- await contractDeployed.methods
+ const awardReceipt = await contractDeployed.methods
.awardItem(tempAccount.address, 'http://my-nft-award')
.send({ ...sendOptions, type });
+ expect(awardReceipt.events).toBeDefined();
+ expect(awardReceipt.events?.Transfer).toBeDefined();
+ expect(awardReceipt.events?.Transfer.event).toBe('Transfer');
+
+ expect(String(awardReceipt.events?.Transfer.returnValues.from).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
const logs = await contractDeployed.getPastEvents('Transfer');
const tokenId = (logs[0] as EventLog)?.returnValues?.tokenId as string;
- await contractDeployed.methods
+ const transferFromReceipt = await contractDeployed.methods
.transferFrom(tempAccount.address, toAccount.address, tokenId)
.send({
...sendOptions,
type,
from: tempAccount.address,
});
+ expect(transferFromReceipt.events).toBeDefined();
+ expect(transferFromReceipt.events?.Transfer).toBeDefined();
+ expect(transferFromReceipt.events?.Transfer.event).toBe('Transfer');
+ expect(
+ String(transferFromReceipt.events?.Transfer.returnValues.from).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(String(transferFromReceipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(String(transferFromReceipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ toAccount.address.toLowerCase(),
+ );
+ expect(String(transferFromReceipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ toAccount.address.toLowerCase(),
+ );
+ expect(transferFromReceipt.events?.Transfer.returnValues.tokenId).toBe(tokenId);
+ expect(transferFromReceipt.events?.Transfer.returnValues[2]).toBe(tokenId);
+
+ expect(transferFromReceipt.events?.Approval).toBeDefined();
+ expect(transferFromReceipt.events?.Approval.event).toBe('Approval');
+ expect(
+ String(transferFromReceipt.events?.Approval.returnValues.owner).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(String(transferFromReceipt.events?.Approval.returnValues[0]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(
+ String(transferFromReceipt.events?.Approval.returnValues.approved).toLowerCase(),
+ ).toBe('0x0000000000000000000000000000000000000000');
+ expect(String(transferFromReceipt.events?.Approval.returnValues[1]).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(transferFromReceipt.events?.Approval.returnValues.tokenId).toBe(tokenId);
+ expect(transferFromReceipt.events?.Approval.returnValues[2]).toBe(tokenId);
expect(
toUpperCaseHex(
@@ -100,22 +167,57 @@ describe('contract', () => {
it.each(['0x1', '0x2'])('should approve and then transferFrom item %p', async type => {
const tempAccount = await createLocalAccount(web3);
const toAccount = await createLocalAccount(web3);
- await contractDeployed.methods
+ const awardReceipt = await contractDeployed.methods
.awardItem(tempAccount.address, 'http://my-nft-award')
.send({ ...sendOptions, type });
+ expect(awardReceipt.events).toBeDefined();
+ expect(awardReceipt.events?.Transfer).toBeDefined();
+ expect(awardReceipt.events?.Transfer.event).toBe('Transfer');
+ expect(String(awardReceipt.events?.Transfer.returnValues.from).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues[0]).toLowerCase()).toBe(
+ '0x0000000000000000000000000000000000000000',
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues.to).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(String(awardReceipt.events?.Transfer.returnValues[1]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
const logs = await contractDeployed.getPastEvents('Transfer');
const tokenId = (logs[0] as EventLog)?.returnValues?.tokenId as string;
- await contractDeployed.methods.approve(toAccount.address, tokenId).send({
- ...sendOptions,
- type,
- from: tempAccount.address,
- });
+ const approveReceipt = await contractDeployed.methods
+ .approve(toAccount.address, tokenId)
+ .send({
+ ...sendOptions,
+ type,
+ from: tempAccount.address,
+ });
+ expect(approveReceipt.events).toBeDefined();
+ expect(approveReceipt.events?.Approval).toBeDefined();
+ expect(approveReceipt.events?.Approval.event).toBe('Approval');
+ expect(String(approveReceipt.events?.Approval.returnValues.owner).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(String(approveReceipt.events?.Approval.returnValues[0]).toLowerCase()).toBe(
+ tempAccount.address.toLowerCase(),
+ );
+ expect(
+ String(approveReceipt.events?.Approval.returnValues.approved).toLowerCase(),
+ ).toBe(toAccount.address.toLowerCase());
+ expect(String(approveReceipt.events?.Approval.returnValues[1]).toLowerCase()).toBe(
+ toAccount.address.toLowerCase(),
+ );
+ expect(approveReceipt.events?.Approval.returnValues.tokenId).toBe(tokenId);
+ expect(approveReceipt.events?.Approval.returnValues[2]).toBe(tokenId);
+
const res = await contractDeployed.methods.getApproved(tokenId).call();
expect(res.toString().toUpperCase()).toBe(toAccount.address.toUpperCase());
- await contractDeployed.methods
+ const safeTransferFromReceipt = await contractDeployed.methods
.safeTransferFrom(tempAccount.address, toAccount.address, tokenId)
.send({
...sendOptions,
@@ -123,6 +225,44 @@ describe('contract', () => {
from: toAccount.address,
});
+ expect(safeTransferFromReceipt.events).toBeDefined();
+ expect(safeTransferFromReceipt.events?.Transfer).toBeDefined();
+ expect(safeTransferFromReceipt.events?.Transfer.event).toBe('Transfer');
+ expect(safeTransferFromReceipt.events?.Approval).toBeDefined();
+ expect(safeTransferFromReceipt.events?.Approval.event).toBe('Approval');
+
+ expect(
+ String(safeTransferFromReceipt.events?.Transfer.returnValues.from).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(safeTransferFromReceipt.events?.Transfer.returnValues[0]).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(safeTransferFromReceipt.events?.Transfer.returnValues.to).toLowerCase(),
+ ).toBe(toAccount.address.toLowerCase());
+ expect(
+ String(safeTransferFromReceipt.events?.Transfer.returnValues[1]).toLowerCase(),
+ ).toBe(toAccount.address.toLowerCase());
+ expect(safeTransferFromReceipt.events?.Transfer.returnValues.tokenId).toBe(tokenId);
+ expect(safeTransferFromReceipt.events?.Transfer.returnValues[2]).toBe(tokenId);
+
+ expect(
+ String(safeTransferFromReceipt.events?.Approval.returnValues.owner).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(safeTransferFromReceipt.events?.Approval.returnValues[0]).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(
+ safeTransferFromReceipt.events?.Approval.returnValues.approved,
+ ).toLowerCase(),
+ ).toBe('0x0000000000000000000000000000000000000000');
+ expect(
+ String(safeTransferFromReceipt.events?.Approval.returnValues[1]).toLowerCase(),
+ ).toBe('0x0000000000000000000000000000000000000000');
+ expect(safeTransferFromReceipt.events?.Approval.returnValues.tokenId).toBe(tokenId);
+ expect(safeTransferFromReceipt.events?.Approval.returnValues[2]).toBe(tokenId);
+
expect(
toUpperCaseHex(
(await contractDeployed.methods.ownerOf(tokenId).call()) as unknown as string,
@@ -136,11 +276,35 @@ describe('contract', () => {
const tempAccount = await createLocalAccount(web3);
const toAccount = await createLocalAccount(web3);
- await contractDeployed.methods.setApprovalForAll(toAccount.address, true).send({
- ...sendOptions,
- type,
- from: tempAccount.address,
- });
+ const setApprovalReceipt = await contractDeployed.methods
+ .setApprovalForAll(toAccount.address, true)
+ .send({
+ ...sendOptions,
+ type,
+ from: tempAccount.address,
+ });
+ expect(setApprovalReceipt.events).toBeDefined();
+ expect(setApprovalReceipt.events?.ApprovalForAll).toBeDefined();
+ expect(setApprovalReceipt.events?.ApprovalForAll.event).toBe('ApprovalForAll');
+
+ expect(
+ String(
+ setApprovalReceipt.events?.ApprovalForAll.returnValues.owner,
+ ).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(setApprovalReceipt.events?.ApprovalForAll.returnValues[0]).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(
+ setApprovalReceipt.events?.ApprovalForAll.returnValues.operator,
+ ).toLowerCase(),
+ ).toBe(toAccount.address.toLowerCase());
+ expect(
+ String(setApprovalReceipt.events?.ApprovalForAll.returnValues[1]).toLowerCase(),
+ ).toBe(toAccount.address.toLowerCase());
+ expect(setApprovalReceipt.events?.ApprovalForAll.returnValues.approved).toBe(true);
+ expect(setApprovalReceipt.events?.ApprovalForAll.returnValues[2]).toBe(true);
expect(
await contractDeployed.methods
@@ -148,12 +312,42 @@ describe('contract', () => {
.call(),
).toBe(true);
- await contractDeployed.methods.setApprovalForAll(toAccount.address, false).send({
- ...sendOptions,
- type,
- from: tempAccount.address,
- });
-
+ const setApprovalForAllReceipt = await contractDeployed.methods
+ .setApprovalForAll(toAccount.address, false)
+ .send({
+ ...sendOptions,
+ type,
+ from: tempAccount.address,
+ });
+ expect(setApprovalForAllReceipt.events).toBeDefined();
+ expect(setApprovalForAllReceipt.events?.ApprovalForAll).toBeDefined();
+ expect(setApprovalForAllReceipt.events?.ApprovalForAll.event).toBe(
+ 'ApprovalForAll',
+ );
+ expect(
+ String(
+ setApprovalForAllReceipt.events?.ApprovalForAll.returnValues.owner,
+ ).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(
+ setApprovalForAllReceipt.events?.ApprovalForAll.returnValues[0],
+ ).toLowerCase(),
+ ).toBe(tempAccount.address.toLowerCase());
+ expect(
+ String(
+ setApprovalForAllReceipt.events?.ApprovalForAll.returnValues.operator,
+ ).toLowerCase(),
+ ).toBe(toAccount.address.toLowerCase());
+ expect(
+ String(
+ setApprovalForAllReceipt.events?.ApprovalForAll.returnValues[1],
+ ).toLowerCase(),
+ ).toBe(toAccount.address.toLowerCase());
+ expect(setApprovalForAllReceipt.events?.ApprovalForAll.returnValues.approved).toBe(
+ false,
+ );
+ expect(setApprovalForAllReceipt.events?.ApprovalForAll.returnValues[2]).toBe(false);
expect(
await contractDeployed.methods
.isApprovedForAll(tempAccount.address, toAccount.address)
diff --git a/packages/web3-eth-contract/test/integration/local_account/contract_overloaded_methods.test.ts b/packages/web3-eth-contract/test/integration/local_account/contract_overloaded_methods.test.ts
index 75e32107d35..3e10c3268e4 100644
--- a/packages/web3-eth-contract/test/integration/local_account/contract_overloaded_methods.test.ts
+++ b/packages/web3-eth-contract/test/integration/local_account/contract_overloaded_methods.test.ts
@@ -20,7 +20,8 @@ import Web3 from 'web3';
// eslint-disable-next-line import/no-extraneous-dependencies
import { Web3Account } from 'web3-eth-accounts';
import { utf8ToHex } from 'web3-utils';
-import { Contract, EventLog } from '../../../src';
+import { EventLog } from 'web3-types';
+import { Contract } from '../../../src';
import { ERC721TokenAbi, ERC721TokenBytecode } from '../../shared_fixtures/build/ERC721Token';
import { getSystemTestProvider, createLocalAccount } from '../../fixtures/system_test_utils';
import { toUpperCaseHex } from '../../shared_fixtures/utils';
diff --git a/packages/web3-eth-contract/test/unit/contract.test.ts b/packages/web3-eth-contract/test/unit/contract.test.ts
index 19f7a768f40..173ac8a5e4e 100644
--- a/packages/web3-eth-contract/test/unit/contract.test.ts
+++ b/packages/web3-eth-contract/test/unit/contract.test.ts
@@ -29,7 +29,17 @@ import { erc721Abi } from '../fixtures/erc721';
import { ERC20TokenAbi } from '../shared_fixtures/build/ERC20Token';
import { processAsync } from '../shared_fixtures/utils';
-jest.mock('web3-eth');
+jest.mock('web3-eth', () => {
+ const allAutoMocked = jest.createMockFromModule('web3-eth');
+ const actual = jest.requireActual('web3-eth');
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return {
+ __esModules: true,
+ // @ts-expect-error ignore allAutoMocked type
+ ...allAutoMocked,
+ decodeEventABI: actual.decodeEventABI,
+ };
+});
describe('Contract', () => {
describe('constructor', () => {
@@ -746,15 +756,14 @@ describe('Contract', () => {
{ config: { defaultAccount: '0x00000000219ab540356cBB839Cbe05303d7705Fa' } },
);
- const spyEthCall = jest
- .spyOn(eth, 'call')
- .mockImplementation(async (_objInstance, _tx) => {
- expect(_tx.to).toBe('0x1230B93ffd14F2F022039675fA3fc3A46eE4C701');
- expect(_tx.input).toBe(
- '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001',
- );
- return '0x00';
- });
+ // @ts-expect-error fix-types
+ const spyEthCall = jest.spyOn(eth, 'call').mockImplementation((_objInstance, _tx) => {
+ expect(_tx.to).toBe('0x1230B93ffd14F2F022039675fA3fc3A46eE4C701');
+ expect(_tx.input).toBe(
+ '0x095ea7b300000000000000000000000000000000219ab540356cbb839cbe05303d7705fa0000000000000000000000000000000000000000000000000000000000000001',
+ );
+ return '0x00';
+ });
await expect(
contract.methods.approve('0x00000000219ab540356cBB839Cbe05303d7705Fa', 1).call(),
@@ -1129,7 +1138,7 @@ describe('Contract', () => {
.send(sendOptions);
await expect(
- processAsync(async (resolve, reject) => {
+ processAsync((resolve, reject) => {
const event = deployedContract.events.allEvents({ fromBlock: 'earliest' });
event.on('error', reject);
diff --git a/packages/web3-eth-contract/test/unit/encode_event_abi.test.ts b/packages/web3-eth-contract/test/unit/encode_event_abi.test.ts
index 6837cbc204f..c4353806ba9 100644
--- a/packages/web3-eth-contract/test/unit/encode_event_abi.test.ts
+++ b/packages/web3-eth-contract/test/unit/encode_event_abi.test.ts
@@ -14,8 +14,8 @@ 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 { AbiEventFragment } from 'web3-types';
-import { ContractOptions, encodeEventABI } from '../../src';
+import { AbiEventFragment, ContractOptions } from 'web3-types';
+import { encodeEventABI } from '../../src';
const contractOptions: ContractOptions = {
address: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md
index e68c56c0613..da6034deeef 100644
--- a/packages/web3-eth/CHANGELOG.md
+++ b/packages/web3-eth/CHANGELOG.md
@@ -196,3 +196,7 @@ Documentation:
### Fixed
- Ensure provider.supportsSubscriptions exists before watching by subscription (#6440)
+
+### Added
+
+- Added `ALL_EVENTS` and `ALL_EVENTS_ABI` constants, `SendTransactionEventsBase` type, `decodeEventABI` method (#6410)
diff --git a/packages/web3-eth/src/constants.ts b/packages/web3-eth/src/constants.ts
index 428c7204170..13a485719a0 100644
--- a/packages/web3-eth/src/constants.ts
+++ b/packages/web3-eth/src/constants.ts
@@ -14,6 +14,14 @@ 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 { FMT_BYTES, FMT_NUMBER } from 'web3-types';
+import { AbiEventFragment, FMT_BYTES, FMT_NUMBER } from 'web3-types';
+
+export const ALL_EVENTS = 'ALLEVENTS';
+export const ALL_EVENTS_ABI = {
+ name: ALL_EVENTS,
+ signature: '',
+ type: 'event',
+ inputs: [],
+} as AbiEventFragment & { signature: string };
export const NUMBER_DATA_FORMAT = { bytes: FMT_BYTES.HEX, number: FMT_NUMBER.NUMBER } as const;
diff --git a/packages/web3-eth/src/index.ts b/packages/web3-eth/src/index.ts
index d5160727be0..d1f1d326832 100644
--- a/packages/web3-eth/src/index.ts
+++ b/packages/web3-eth/src/index.ts
@@ -53,7 +53,9 @@ import 'setimmediate';
import { Web3Eth } from './web3_eth.js';
export * from './web3_eth.js';
+export * from './utils/decoding.js';
export * from './schemas.js';
+export * from './constants.js';
export * from './types.js';
export * from './validation.js';
export * from './rpc_method_wrappers.js';
diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts
index 866ca7aab6c..542b1b36d88 100644
--- a/packages/web3-eth/src/rpc_method_wrappers.ts
+++ b/packages/web3-eth/src/rpc_method_wrappers.ts
@@ -23,7 +23,6 @@ import {
DataFormat,
DEFAULT_RETURN_FORMAT,
EthExecutionAPI,
- TransactionWithSenderAPI,
SignedTransactionInfoAPI,
Web3BaseWalletAccount,
Address,
@@ -53,14 +52,7 @@ import { Web3Context, Web3PromiEvent } from 'web3-core';
import { format, hexToBytes, bytesToUint8Array, numberToHex } from 'web3-utils';
import { TransactionFactory } from 'web3-eth-accounts';
import { isBlockTag, isBytes, isNullish, isString } from 'web3-validator';
-import {
- ContractExecutionError,
- InvalidResponseError,
- SignatureError,
- TransactionRevertedWithoutReasonError,
- TransactionRevertInstructionError,
- TransactionRevertWithCustomError,
-} from 'web3-errors';
+import { SignatureError } from 'web3-errors';
import { ethRpcMethods } from 'web3-rpc-methods';
import { decodeSignedTransaction } from './utils/decode_signed_transaction.js';
@@ -83,17 +75,12 @@ import {
import { getTransactionFromOrToAttr } from './utils/transaction_builder.js';
import { formatTransaction } from './utils/format_transaction.js';
// eslint-disable-next-line import/no-cycle
-import { getTransactionGasPricing } from './utils/get_transaction_gas_pricing.js';
-// eslint-disable-next-line import/no-cycle
import { trySendTransaction } from './utils/try_send_transaction.js';
// eslint-disable-next-line import/no-cycle
import { waitForTransactionReceipt } from './utils/wait_for_transaction_receipt.js';
-import { watchTransactionForConfirmations } from './utils/watch_transaction_for_confirmations.js';
import { NUMBER_DATA_FORMAT } from './constants.js';
// eslint-disable-next-line import/no-cycle
-import { getTransactionError } from './utils/get_transaction_error.js';
-// eslint-disable-next-line import/no-cycle
-import { getRevertReason } from './utils/get_revert_reason.js';
+import { SendTxHelper } from './utils/send_tx_helper.js';
/**
* View additional documentations here: {@link Web3Eth.getProtocolVersion}
@@ -501,7 +488,18 @@ export function sendTransaction<
(resolve, reject) => {
setImmediate(() => {
(async () => {
- let transactionFormatted = formatTransaction(
+ const sendTxHelper = new SendTxHelper({
+ web3Context,
+ promiEvent,
+ options,
+ returnFormat,
+ });
+
+ let transactionFormatted:
+ | Transaction
+ | TransactionWithFromLocalWalletIndex
+ | TransactionWithToLocalWalletIndex
+ | TransactionWithFromAndToLocalWalletIndex = formatTransaction(
{
...transaction,
from: getTransactionFromOrToAttr('from', web3Context, transaction),
@@ -510,98 +508,40 @@ export function sendTransaction<
ETH_DATA_FORMAT,
);
- if (
- !options?.ignoreGasPricing &&
- isNullish(transactionFormatted.gasPrice) &&
- (isNullish(transaction.maxPriorityFeePerGas) ||
- isNullish(transaction.maxFeePerGas))
- ) {
- transactionFormatted = {
- ...transactionFormatted,
- // TODO gasPrice, maxPriorityFeePerGas, maxFeePerGas
- // should not be included if undefined, but currently are
- ...(await getTransactionGasPricing(
- transactionFormatted,
- web3Context,
- ETH_DATA_FORMAT,
- )),
- };
- }
try {
- if (options.checkRevertBeforeSending !== false) {
- const reason = await getRevertReason(
- web3Context,
- transactionFormatted as TransactionCall,
- options.contractAbi,
- );
- if (reason !== undefined) {
- const error = await getTransactionError(
- web3Context,
- transactionFormatted as TransactionCall,
- undefined,
- undefined,
- options.contractAbi,
- reason,
- );
-
- if (promiEvent.listenerCount('error') > 0) {
- promiEvent.emit('error', error);
- }
-
- reject(error);
- return;
- }
- }
+ transactionFormatted = await sendTxHelper.populateGasPrice({
+ transaction,
+ transactionFormatted,
+ });
- if (promiEvent.listenerCount('sending') > 0) {
- promiEvent.emit('sending', transactionFormatted);
- }
+ await sendTxHelper.checkRevertBeforeSending(
+ transactionFormatted as TransactionCall,
+ );
+
+ sendTxHelper.emitSending(transactionFormatted);
- let transactionHash: HexString;
let wallet: Web3BaseWalletAccount | undefined;
if (web3Context.wallet && !isNullish(transactionFormatted.from)) {
- wallet = web3Context.wallet.get(transactionFormatted.from);
- }
-
- if (wallet) {
- const signedTransaction = await wallet.signTransaction(
- transactionFormatted,
- );
-
- transactionHash = await trySendTransaction(
- web3Context,
- async (): Promise =>
- ethRpcMethods.sendRawTransaction(
- web3Context.requestManager,
- signedTransaction.rawTransaction,
- ),
- signedTransaction.transactionHash,
- );
- } else {
- transactionHash = await trySendTransaction(
- web3Context,
- async (): Promise =>
- ethRpcMethods.sendTransaction(
- web3Context.requestManager,
- transactionFormatted as Partial,
- ),
+ wallet = web3Context.wallet.get(
+ (transactionFormatted as Transaction).from as string,
);
}
+ const transactionHash: HexString = await sendTxHelper.signAndSend({
+ wallet,
+ tx: transactionFormatted,
+ });
+
const transactionHashFormatted = format(
{ format: 'bytes32' },
transactionHash as Bytes,
returnFormat,
);
-
- if (promiEvent.listenerCount('sent') > 0) {
- promiEvent.emit('sent', transactionFormatted);
- }
-
- if (promiEvent.listenerCount('transactionHash') > 0) {
- promiEvent.emit('transactionHash', transactionHashFormatted);
- }
+ sendTxHelper.emitSent(transactionFormatted);
+ sendTxHelper.emitTransactionHash(
+ transactionHashFormatted as string & Uint8Array,
+ );
const transactionReceipt = await waitForTransactionReceipt(
web3Context,
@@ -609,78 +549,30 @@ export function sendTransaction<
returnFormat,
);
- const transactionReceiptFormatted = format(
- transactionReceiptSchema,
- transactionReceipt,
- returnFormat,
+ const transactionReceiptFormatted = sendTxHelper.getReceiptWithEvents(
+ format(transactionReceiptSchema, transactionReceipt, returnFormat),
);
- if (promiEvent.listenerCount('receipt') > 0) {
- promiEvent.emit('receipt', transactionReceiptFormatted);
- }
+ sendTxHelper.emitReceipt(transactionReceiptFormatted);
- if (options?.transactionResolver) {
- resolve(
- options?.transactionResolver(
- transactionReceiptFormatted,
- ) as unknown as ResolveType,
- );
- } else if (transactionReceipt.status === BigInt(0)) {
- const error = await getTransactionError(
- web3Context,
- transactionFormatted as TransactionCall,
- transactionReceiptFormatted,
- undefined,
- options?.contractAbi,
- );
-
- if (promiEvent.listenerCount('error') > 0) {
- promiEvent.emit('error', error);
- }
-
- reject(error);
- } else {
- resolve(transactionReceiptFormatted as unknown as ResolveType);
- }
+ resolve(
+ await sendTxHelper.handleResolve({
+ receipt: transactionReceiptFormatted,
+ tx: transactionFormatted as TransactionCall,
+ }),
+ );
- if (promiEvent.listenerCount('confirmation') > 0) {
- watchTransactionForConfirmations<
- ReturnFormat,
- SendTransactionEvents,
- ResolveType
- >(
- web3Context,
- promiEvent,
- transactionReceiptFormatted as TransactionReceipt,
- transactionHash,
- returnFormat,
- );
- }
+ sendTxHelper.emitConfirmation({
+ receipt: transactionReceiptFormatted,
+ transactionHash,
+ });
} catch (error) {
- let _error = error;
-
- if (_error instanceof ContractExecutionError && web3Context.handleRevert) {
- _error = await getTransactionError(
- web3Context,
- transactionFormatted as TransactionCall,
- undefined,
- undefined,
- options?.contractAbi,
- );
- }
-
- if (
- (_error instanceof InvalidResponseError ||
- _error instanceof ContractExecutionError ||
- _error instanceof TransactionRevertWithCustomError ||
- _error instanceof TransactionRevertedWithoutReasonError ||
- _error instanceof TransactionRevertInstructionError) &&
- promiEvent.listenerCount('error') > 0
- ) {
- promiEvent.emit('error', _error);
- }
-
- reject(_error);
+ reject(
+ await sendTxHelper.handleError({
+ error,
+ tx: transactionFormatted as TransactionCall,
+ }),
+ );
}
})() as unknown;
});
@@ -709,6 +601,12 @@ export function sendSignedTransaction<
(resolve, reject) => {
setImmediate(() => {
(async () => {
+ const sendTxHelper = new SendTxHelper({
+ web3Context,
+ promiEvent,
+ options,
+ returnFormat,
+ });
// Formatting signedTransaction to be send to RPC endpoint
const signedTransactionFormattedHex = format(
{ format: 'bytes' },
@@ -729,34 +627,11 @@ export function sendSignedTransaction<
};
try {
- if (options.checkRevertBeforeSending !== false) {
- const reason = await getRevertReason(
- web3Context,
- unSerializedTransactionWithFrom as TransactionCall,
- options.contractAbi,
- );
- if (reason !== undefined) {
- const error = await getTransactionError(
- web3Context,
- unSerializedTransactionWithFrom as TransactionCall,
- undefined,
- undefined,
- options.contractAbi,
- reason,
- );
-
- if (promiEvent.listenerCount('error') > 0) {
- promiEvent.emit('error', error);
- }
-
- reject(error);
- return;
- }
- }
+ await sendTxHelper.checkRevertBeforeSending(
+ unSerializedTransactionWithFrom as TransactionCall,
+ );
- if (promiEvent.listenerCount('sending') > 0) {
- promiEvent.emit('sending', signedTransactionFormattedHex);
- }
+ sendTxHelper.emitSending(signedTransactionFormattedHex);
const transactionHash = await trySendTransaction(
web3Context,
@@ -767,9 +642,7 @@ export function sendSignedTransaction<
),
);
- if (promiEvent.listenerCount('sent') > 0) {
- promiEvent.emit('sent', signedTransactionFormattedHex);
- }
+ sendTxHelper.emitSent(signedTransactionFormattedHex);
const transactionHashFormatted = format(
{ format: 'bytes32' },
@@ -777,9 +650,9 @@ export function sendSignedTransaction<
returnFormat,
);
- if (promiEvent.listenerCount('transactionHash') > 0) {
- promiEvent.emit('transactionHash', transactionHashFormatted);
- }
+ sendTxHelper.emitTransactionHash(
+ transactionHashFormatted as string & Uint8Array,
+ );
const transactionReceipt = await waitForTransactionReceipt(
web3Context,
@@ -787,78 +660,30 @@ export function sendSignedTransaction<
returnFormat,
);
- const transactionReceiptFormatted = format(
- transactionReceiptSchema,
- transactionReceipt,
- returnFormat,
+ const transactionReceiptFormatted = sendTxHelper.getReceiptWithEvents(
+ format(transactionReceiptSchema, transactionReceipt, returnFormat),
);
- if (promiEvent.listenerCount('receipt') > 0) {
- promiEvent.emit('receipt', transactionReceiptFormatted);
- }
-
- if (options?.transactionResolver) {
- resolve(
- options?.transactionResolver(
- transactionReceiptFormatted,
- ) as unknown as ResolveType,
- );
- } else if (transactionReceipt.status === BigInt(0)) {
- const error = await getTransactionError(
- web3Context,
- unSerializedTransactionWithFrom as TransactionCall,
- transactionReceiptFormatted,
- undefined,
- options?.contractAbi,
- );
-
- if (promiEvent.listenerCount('error') > 0) {
- promiEvent.emit('error', error);
- }
+ sendTxHelper.emitReceipt(transactionReceiptFormatted);
- reject(error);
- } else {
- resolve(transactionReceiptFormatted as unknown as ResolveType);
- }
+ resolve(
+ await sendTxHelper.handleResolve({
+ receipt: transactionReceiptFormatted,
+ tx: unSerializedTransactionWithFrom as TransactionCall,
+ }),
+ );
- if (promiEvent.listenerCount('confirmation') > 0) {
- watchTransactionForConfirmations<
- ReturnFormat,
- SendSignedTransactionEvents,
- ResolveType
- >(
- web3Context,
- promiEvent,
- transactionReceiptFormatted as TransactionReceipt,
- transactionHash,
- returnFormat,
- );
- }
+ sendTxHelper.emitConfirmation({
+ receipt: transactionReceiptFormatted,
+ transactionHash,
+ });
} catch (error) {
- let _error = error;
-
- if (_error instanceof ContractExecutionError && web3Context.handleRevert) {
- _error = await getTransactionError(
- web3Context,
- unSerializedTransactionWithFrom as TransactionCall,
- undefined,
- undefined,
- options?.contractAbi,
- );
- }
-
- if (
- (_error instanceof InvalidResponseError ||
- _error instanceof ContractExecutionError ||
- _error instanceof TransactionRevertWithCustomError ||
- _error instanceof TransactionRevertedWithoutReasonError ||
- _error instanceof TransactionRevertInstructionError) &&
- promiEvent.listenerCount('error') > 0
- ) {
- promiEvent.emit('error', _error);
- }
-
- reject(_error);
+ reject(
+ await sendTxHelper.handleError({
+ error,
+ tx: unSerializedTransactionWithFrom as TransactionCall,
+ }),
+ );
}
})() as unknown;
});
diff --git a/packages/web3-eth/src/types.ts b/packages/web3-eth/src/types.ts
index 103a2829c8a..ae97084ea72 100644
--- a/packages/web3-eth/src/types.ts
+++ b/packages/web3-eth/src/types.ts
@@ -36,9 +36,9 @@ import {
export type InternalTransaction = FormatType;
-export type SendTransactionEvents = {
- sending: FormatType;
- sent: FormatType;
+export type SendTransactionEventsBase = {
+ sending: FormatType;
+ sent: FormatType;
transactionHash: FormatType;
receipt: FormatType;
confirmation: {
@@ -54,23 +54,12 @@ export type SendTransactionEvents = {
| ContractExecutionError;
};
-export type SendSignedTransactionEvents = {
- sending: FormatType;
- sent: FormatType;
- transactionHash: FormatType;
- receipt: FormatType;
- confirmation: {
- confirmations: FormatType;
- receipt: FormatType;
- latestBlockHash: FormatType;
- };
- error:
- | TransactionRevertedWithoutReasonError>
- | TransactionRevertInstructionError>
- | TransactionRevertWithCustomError>
- | InvalidResponseError
- | ContractExecutionError;
-};
+export type SendTransactionEvents = SendTransactionEventsBase<
+ ReturnFormat,
+ Transaction
+>;
+export type SendSignedTransactionEvents =
+ SendTransactionEventsBase;
export interface SendTransactionOptions {
ignoreGasPricing?: boolean;
diff --git a/packages/web3-eth/src/utils/decoding.ts b/packages/web3-eth/src/utils/decoding.ts
new file mode 100644
index 00000000000..f4b61c0a5ac
--- /dev/null
+++ b/packages/web3-eth/src/utils/decoding.ts
@@ -0,0 +1,95 @@
+/*
+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 { format } from 'web3-utils';
+
+import {
+ AbiEventFragment,
+ LogsInput,
+ DataFormat,
+ DEFAULT_RETURN_FORMAT,
+ EventLog,
+ ContractAbiWithSignature,
+} from 'web3-types';
+
+import { decodeLog } from 'web3-eth-abi';
+
+import { logSchema } from '../schemas.js';
+import { ALL_EVENTS } from '../constants.js';
+
+export const decodeEventABI = (
+ event: AbiEventFragment & { signature: string },
+ data: LogsInput,
+ jsonInterface: ContractAbiWithSignature,
+ returnFormat: DataFormat = DEFAULT_RETURN_FORMAT,
+): EventLog => {
+ let modifiedEvent = { ...event };
+
+ const result = format(logSchema, data, returnFormat);
+
+ // if allEvents get the right event
+ if ([ALL_EVENTS, 'allEvents'].includes(modifiedEvent.name)) {
+ const matchedEvent = jsonInterface.find(j => j.signature === data.topics[0]);
+ if (matchedEvent) {
+ modifiedEvent = matchedEvent as AbiEventFragment & { signature: string };
+ } else {
+ modifiedEvent = { anonymous: true } as unknown as AbiEventFragment & {
+ signature: string;
+ };
+ }
+ }
+
+ // create empty inputs if none are present (e.g. anonymous events on allEvents)
+ modifiedEvent.inputs = modifiedEvent.inputs ?? event.inputs ?? [];
+
+ // Handle case where an event signature shadows the current ABI with non-identical
+ // arg indexing. If # of topics doesn't match, event is anon.
+ if (!modifiedEvent.anonymous) {
+ let indexedInputs = 0;
+ (modifiedEvent.inputs ?? []).forEach(input => {
+ if (input.indexed) {
+ indexedInputs += 1;
+ }
+ });
+
+ if (indexedInputs > 0 && data?.topics && data?.topics.length !== indexedInputs + 1) {
+ // checks if event is anonymous
+ modifiedEvent = {
+ ...modifiedEvent,
+ anonymous: true,
+ inputs: [],
+ };
+ }
+ }
+
+ const argTopics = modifiedEvent.anonymous ? data.topics : (data.topics ?? []).slice(1);
+
+ return {
+ ...result,
+ returnValues: decodeLog([...(modifiedEvent.inputs ?? [])], data.data, argTopics),
+ event: modifiedEvent.name,
+ signature:
+ modifiedEvent.anonymous || !data.topics || data.topics.length === 0 || !data.topics[0]
+ ? undefined
+ : data.topics[0],
+
+ raw: {
+ data: data.data,
+ topics: data.topics,
+ },
+ };
+};
diff --git a/packages/web3-eth/src/utils/send_tx_helper.ts b/packages/web3-eth/src/utils/send_tx_helper.ts
new file mode 100644
index 00000000000..3cc767449b6
--- /dev/null
+++ b/packages/web3-eth/src/utils/send_tx_helper.ts
@@ -0,0 +1,299 @@
+/*
+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 {
+ ETH_DATA_FORMAT,
+ FormatType,
+ DataFormat,
+ EthExecutionAPI,
+ TransactionWithSenderAPI,
+ Web3BaseWalletAccount,
+ HexString,
+ TransactionReceipt,
+ Transaction,
+ TransactionCall,
+ TransactionWithFromLocalWalletIndex,
+ TransactionWithToLocalWalletIndex,
+ TransactionWithFromAndToLocalWalletIndex,
+ LogsInput,
+ TransactionHash,
+ ContractAbiWithSignature,
+} from 'web3-types';
+import { Web3Context, Web3EventEmitter, Web3PromiEvent } from 'web3-core';
+import { isNullish } from 'web3-validator';
+import {
+ ContractExecutionError,
+ InvalidResponseError,
+ TransactionRevertedWithoutReasonError,
+ TransactionRevertInstructionError,
+ TransactionRevertWithCustomError,
+} from 'web3-errors';
+import { ethRpcMethods } from 'web3-rpc-methods';
+
+import {
+ SendSignedTransactionEvents,
+ SendTransactionEvents,
+ SendTransactionOptions,
+} from '../types.js';
+// eslint-disable-next-line import/no-cycle
+import { getTransactionGasPricing } from './get_transaction_gas_pricing.js';
+// eslint-disable-next-line import/no-cycle
+import { trySendTransaction } from './try_send_transaction.js';
+// eslint-disable-next-line import/no-cycle
+import { watchTransactionForConfirmations } from './watch_transaction_for_confirmations.js';
+import { ALL_EVENTS_ABI } from '../constants.js';
+// eslint-disable-next-line import/no-cycle
+import { getTransactionError } from './get_transaction_error.js';
+// eslint-disable-next-line import/no-cycle
+import { getRevertReason } from './get_revert_reason.js';
+import { decodeEventABI } from './decoding.js';
+
+export class SendTxHelper<
+ ReturnFormat extends DataFormat,
+ ResolveType = FormatType,
+ TxType =
+ | Transaction
+ | TransactionWithFromLocalWalletIndex
+ | TransactionWithToLocalWalletIndex
+ | TransactionWithFromAndToLocalWalletIndex,
+> {
+ private readonly web3Context: Web3Context;
+ private readonly promiEvent: Web3PromiEvent<
+ ResolveType,
+ SendSignedTransactionEvents | SendTransactionEvents
+ >;
+ private readonly options: SendTransactionOptions = {
+ checkRevertBeforeSending: true,
+ };
+ private readonly returnFormat: ReturnFormat;
+ public constructor({
+ options,
+ web3Context,
+ promiEvent,
+ returnFormat,
+ }: {
+ web3Context: Web3Context;
+ options: SendTransactionOptions;
+ promiEvent: Web3PromiEvent<
+ ResolveType,
+ SendSignedTransactionEvents | SendTransactionEvents
+ >;
+ returnFormat: ReturnFormat;
+ }) {
+ this.options = options;
+ this.web3Context = web3Context;
+ this.promiEvent = promiEvent;
+ this.returnFormat = returnFormat;
+ }
+
+ public getReceiptWithEvents(data: TransactionReceipt): ResolveType {
+ const result = { ...(data ?? {}) };
+ if (this.options?.contractAbi && result.logs && result.logs.length > 0) {
+ result.events = {};
+ for (const log of result.logs) {
+ const event = decodeEventABI(
+ ALL_EVENTS_ABI,
+ log as LogsInput,
+ this.options?.contractAbi as ContractAbiWithSignature,
+ this.returnFormat,
+ );
+ if (event.event) {
+ result.events[event.event] = event;
+ }
+ }
+ }
+
+ return result as unknown as ResolveType;
+ }
+
+ public async checkRevertBeforeSending(tx: TransactionCall) {
+ if (this.options.checkRevertBeforeSending !== false) {
+ const reason = await getRevertReason(this.web3Context, tx, this.options.contractAbi);
+ if (reason !== undefined) {
+ throw await getTransactionError(
+ this.web3Context,
+ tx,
+ undefined,
+ undefined,
+ this.options.contractAbi,
+ reason,
+ );
+ }
+ }
+ }
+
+ public emitSending(tx: TxType | HexString) {
+ if (this.promiEvent.listenerCount('sending') > 0) {
+ this.promiEvent.emit('sending', tx);
+ }
+ }
+
+ public async populateGasPrice({
+ transactionFormatted,
+ transaction,
+ }: {
+ transactionFormatted: TxType;
+ transaction: TxType;
+ }): Promise {
+ let result = transactionFormatted;
+ if (
+ !this.options?.ignoreGasPricing &&
+ isNullish((transactionFormatted as Transaction).gasPrice) &&
+ (isNullish((transaction as Transaction).maxPriorityFeePerGas) ||
+ isNullish((transaction as Transaction).maxFeePerGas))
+ ) {
+ result = {
+ ...transactionFormatted,
+ // TODO gasPrice, maxPriorityFeePerGas, maxFeePerGas
+ // should not be included if undefined, but currently are
+ ...(await getTransactionGasPricing(
+ transactionFormatted,
+ this.web3Context,
+ ETH_DATA_FORMAT,
+ )),
+ };
+ }
+
+ return result;
+ }
+
+ public async signAndSend({
+ wallet,
+ tx,
+ }: {
+ wallet: Web3BaseWalletAccount | undefined;
+ tx: TxType;
+ }) {
+ if (wallet) {
+ const signedTransaction = await wallet.signTransaction(tx);
+
+ return trySendTransaction(
+ this.web3Context,
+ async (): Promise =>
+ ethRpcMethods.sendRawTransaction(
+ this.web3Context.requestManager,
+ signedTransaction.rawTransaction,
+ ),
+ signedTransaction.transactionHash,
+ );
+ }
+ return trySendTransaction(
+ this.web3Context,
+ async (): Promise =>
+ ethRpcMethods.sendTransaction(
+ this.web3Context.requestManager,
+ tx as Partial,
+ ),
+ );
+ }
+
+ public emitSent(tx: TxType | HexString) {
+ if (this.promiEvent.listenerCount('sent') > 0) {
+ this.promiEvent.emit('sent', tx);
+ }
+ }
+ public emitTransactionHash(hash: string & Uint8Array) {
+ if (this.promiEvent.listenerCount('transactionHash') > 0) {
+ this.promiEvent.emit('transactionHash', hash);
+ }
+ }
+
+ public emitReceipt(receipt: ResolveType) {
+ if (this.promiEvent.listenerCount('receipt') > 0) {
+ (
+ this.promiEvent as Web3EventEmitter<
+ SendTransactionEvents | SendSignedTransactionEvents
+ >
+ ).emit(
+ 'receipt',
+ // @ts-expect-error unknown type fix
+ receipt,
+ );
+ }
+ }
+
+ public async handleError({ error, tx }: { error: unknown; tx: TransactionCall }) {
+ let _error = error;
+
+ if (_error instanceof ContractExecutionError && this.web3Context.handleRevert) {
+ _error = await getTransactionError(
+ this.web3Context,
+ tx,
+ undefined,
+ undefined,
+ this.options?.contractAbi,
+ );
+ }
+
+ if (
+ (_error instanceof InvalidResponseError ||
+ _error instanceof ContractExecutionError ||
+ _error instanceof TransactionRevertWithCustomError ||
+ _error instanceof TransactionRevertedWithoutReasonError ||
+ _error instanceof TransactionRevertInstructionError) &&
+ this.promiEvent.listenerCount('error') > 0
+ ) {
+ this.promiEvent.emit('error', _error);
+ }
+
+ return _error;
+ }
+
+ public emitConfirmation({
+ receipt,
+ transactionHash,
+ }: {
+ receipt: ResolveType;
+ transactionHash: TransactionHash;
+ }) {
+ if (this.promiEvent.listenerCount('confirmation') > 0) {
+ watchTransactionForConfirmations<
+ ReturnFormat,
+ SendSignedTransactionEvents | SendTransactionEvents,
+ ResolveType
+ >(
+ this.web3Context,
+ this.promiEvent,
+ receipt as unknown as TransactionReceipt,
+ transactionHash,
+ this.returnFormat,
+ );
+ }
+ }
+
+ public async handleResolve({ receipt, tx }: { receipt: ResolveType; tx: TransactionCall }) {
+ if (this.options?.transactionResolver) {
+ return this.options?.transactionResolver(receipt as unknown as TransactionReceipt);
+ }
+ if ((receipt as unknown as TransactionReceipt).status === BigInt(0)) {
+ const error = await getTransactionError(
+ this.web3Context,
+ tx,
+ // @ts-expect-error unknown type fix
+ receipt,
+ undefined,
+ this.options?.contractAbi,
+ );
+ if (this.promiEvent.listenerCount('error') > 0) {
+ this.promiEvent.emit('error', error);
+ }
+
+ throw error;
+ } else {
+ return receipt;
+ }
+ }
+}
diff --git a/packages/web3-eth-contract/test/fixtures/encoding.ts b/packages/web3-eth/test/fixtures/decoding.ts
similarity index 60%
rename from packages/web3-eth-contract/test/fixtures/encoding.ts
rename to packages/web3-eth/test/fixtures/decoding.ts
index 7bcd63d9873..e548f33acc6 100644
--- a/packages/web3-eth-contract/test/fixtures/encoding.ts
+++ b/packages/web3-eth/test/fixtures/decoding.ts
@@ -17,6 +17,38 @@ along with web3.js. If not, see .
import { AbiEventFragment, LogsInput } from 'web3-types';
export const decodeEventABIData: [AbiEventFragment & { signature: string }, LogsInput, any][] = [
+ [
+ {
+ // unindexed event with some indexed
+ type: 'event',
+ inputs: [
+ { name: 'a', type: 'string', indexed: true },
+ { name: 'b', type: 'uint', indexed: false },
+ { name: 'a', type: 'string', indexed: false },
+ ],
+ name: 'EventNotAnonymous',
+ signature: '0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5',
+ },
+ {
+ address: '',
+ topics: ['0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5'],
+ data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000',
+ },
+ {
+ address: '',
+ topics: ['0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5'],
+ data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000',
+ returnValues: {
+ __length__: 0,
+ },
+ event: 'EventNotAnonymous',
+ signature: undefined,
+ raw: {
+ data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000',
+ topics: ['0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5'],
+ },
+ },
+ ],
[
{
// unindexed event
@@ -38,8 +70,14 @@ export const decodeEventABIData: [AbiEventFragment & { signature: string }, Logs
address: '',
topics: ['0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5'],
data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000',
- id: undefined,
- returnValues: { '0': 'a', '1': '24', '2': 'c', __length__: 3, a: 'c', b: '24' },
+ returnValues: {
+ '0': 'a',
+ '1': BigInt(24),
+ '2': 'c',
+ __length__: 3,
+ a: 'c',
+ b: BigInt(24),
+ },
event: 'EventNotAnonymous',
signature: '0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5',
raw: {
@@ -48,6 +86,33 @@ export const decodeEventABIData: [AbiEventFragment & { signature: string }, Logs
},
},
],
+ [
+ {
+ // all events
+ type: 'event',
+ name: 'allEvents',
+ signature: '',
+ },
+ {
+ address: '',
+ topics: ['0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5'],
+ data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000',
+ },
+ {
+ address: '',
+ topics: ['0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5'],
+ data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000',
+ returnValues: {
+ __length__: 0,
+ },
+ event: undefined,
+ signature: undefined,
+ raw: {
+ data: '0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016300000000000000000000000000000000000000000000000000000000000000',
+ topics: ['0x7bbee60e68739c7319c204bae2f54caab4114edf476c64bfc5be98af25f446f5'],
+ },
+ },
+ ],
[
{
// indexed event
@@ -70,13 +135,47 @@ export const decodeEventABIData: [AbiEventFragment & { signature: string }, Logs
'0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
'0x000000000000000000000000000000000000000000000000000000000000007b',
],
- data: '0x',
- id: undefined,
- returnValues: { '0': '123', __length__: 1, a: '123' },
+ data: '',
+ returnValues: { '0': BigInt(123), __length__: 1, a: BigInt(123) },
event: 'EventIndexed',
signature: '0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
raw: {
- data: '0x',
+ data: '',
+ topics: [
+ '0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
+ '0x000000000000000000000000000000000000000000000000000000000000007b',
+ ],
+ },
+ },
+ ],
+ [
+ {
+ // indexed all events
+ type: 'event',
+ inputs: [{ name: 'a', type: 'uint256', indexed: true }],
+ name: 'allEvents',
+ signature: '0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
+ },
+ {
+ address: '',
+ topics: [
+ '0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
+ '0x000000000000000000000000000000000000000000000000000000000000007b',
+ ],
+ data: '',
+ },
+ {
+ address: '',
+ topics: [
+ '0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
+ '0x000000000000000000000000000000000000000000000000000000000000007b',
+ ],
+ data: '',
+ returnValues: { '0': BigInt(123), __length__: 1, a: BigInt(123) },
+ event: undefined,
+ signature: '0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
+ raw: {
+ data: '',
topics: [
'0xdd64d7f331676de21d95ea9f7eb8585b688f72afec29a51ff4502fd5a6ae19e7',
'0x000000000000000000000000000000000000000000000000000000000000007b',
@@ -106,15 +205,14 @@ export const decodeEventABIData: [AbiEventFragment & { signature: string }, Logs
address: '',
topics: [],
data: '0x0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000000000000000000000000000000000000000002307800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016200000000000000000000000000000000000000000000000000000000000000',
- id: undefined,
returnValues: {
'0': '0x',
- '1': '12',
- '2': '192',
+ '1': BigInt(12),
+ '2': BigInt(192),
__length__: 3,
a: '0x',
- b: '12',
- c: '192',
+ b: BigInt(12),
+ c: BigInt(192),
},
event: '',
signature: undefined,
@@ -145,15 +243,14 @@ export const decodeEventABIData: [AbiEventFragment & { signature: string }, Logs
address: '',
topics: [],
data: '0x0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000000000000000000000000000000000000000002307800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016200000000000000000000000000000000000000000000000000000000000000',
- id: undefined,
returnValues: {
'0': '0x',
- '1': '12',
- '2': '192',
+ '1': BigInt(12),
+ '2': BigInt(192),
__length__: 3,
a: '0x',
- b: '12',
- c: '192',
+ b: BigInt(12),
+ c: BigInt(192),
},
event: '',
signature: undefined,
diff --git a/packages/web3-eth/test/fixtures/erc20.ts b/packages/web3-eth/test/fixtures/erc20.ts
new file mode 100644
index 00000000000..17ce176c7d8
--- /dev/null
+++ b/packages/web3-eth/test/fixtures/erc20.ts
@@ -0,0 +1,175 @@
+/*
+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 .
+*/
+export const ERC20TokenAbi = [
+ {
+ inputs: [{ internalType: 'uint256', name: 'initialSupply', type: 'uint256' }],
+ stateMutability: 'nonpayable',
+ type: 'constructor',
+ signature: '',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'owner', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'spender', type: 'address' },
+ { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256' },
+ ],
+ name: 'Approval',
+ type: 'event',
+ signature: '0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925',
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: 'from', type: 'address' },
+ { indexed: true, internalType: 'address', name: 'to', type: 'address' },
+ { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256' },
+ ],
+ name: 'Transfer',
+ type: 'event',
+ signature: '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'owner', type: 'address' },
+ { internalType: 'address', name: 'spender', type: 'address' },
+ ],
+ name: 'allowance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ signature: '0xdd62ed3e',
+ constant: true,
+ payable: false,
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'approve',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ signature: '0x095ea7b3',
+ constant: false,
+ payable: false,
+ },
+ {
+ inputs: [{ internalType: 'address', name: 'account', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ signature: '0x70a08231',
+ constant: true,
+ payable: false,
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'view',
+ type: 'function',
+ signature: '0x313ce567',
+ constant: true,
+ payable: false,
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'subtractedValue', type: 'uint256' },
+ ],
+ name: 'decreaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ signature: '0xa457c2d7',
+ constant: false,
+ payable: false,
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'spender', type: 'address' },
+ { internalType: 'uint256', name: 'addedValue', type: 'uint256' },
+ ],
+ name: 'increaseAllowance',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ signature: '0x39509351',
+ constant: false,
+ payable: false,
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ signature: '0x06fdde03',
+ constant: true,
+ payable: false,
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function',
+ signature: '0x95d89b41',
+ constant: true,
+ payable: false,
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function',
+ signature: '0x18160ddd',
+ constant: true,
+ payable: false,
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transfer',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ signature: '0xa9059cbb',
+ constant: false,
+ payable: false,
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: 'from', type: 'address' },
+ { internalType: 'address', name: 'to', type: 'address' },
+ { internalType: 'uint256', name: 'amount', type: 'uint256' },
+ ],
+ name: 'transferFrom',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function',
+ signature: '0x23b872dd',
+ constant: false,
+ payable: false,
+ },
+] as const;
diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts
index 3d8f824fd6f..b3587a47c45 100644
--- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts
+++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts
@@ -61,6 +61,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3Eth.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
+ expect(response.events).toBeUndefined();
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
expect(minedTransactionData).toMatchObject(transaction);
@@ -84,6 +85,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3EthWithWallet.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
+ expect(response.events).toBeUndefined();
const minedTransactionData = await web3EthWithWallet.getTransaction(
response.transactionHash,
@@ -114,6 +116,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3EthWithWallet.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
+ expect(response.events).toBeUndefined();
const minedTransactionData = await web3EthWithWallet.getTransaction(
response.transactionHash,
@@ -148,6 +151,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3EthWithWallet.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
+ expect(response.events).toBeUndefined();
const minedTransactionData = await web3EthWithWallet.getTransaction(
response.transactionHash,
@@ -167,6 +171,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3Eth.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
+ expect(response.events).toBeUndefined();
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
expect(minedTransactionData).toMatchObject(transaction);
@@ -180,6 +185,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3Eth.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
+ expect(response.events).toBeUndefined();
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
expect(minedTransactionData).toMatchObject(transaction);
@@ -199,6 +205,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3Eth.sendTransaction(transaction);
expect(response.status).toBe(BigInt(1));
+ expect(response.events).toBeUndefined();
expect(response.contractAddress).toBeDefined();
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
@@ -221,6 +228,7 @@ describe('Web3Eth.sendTransaction', () => {
input: contractFunctionCall,
};
const response = await web3Eth.sendTransaction(transaction);
+ expect(response.events).toBeUndefined();
expect(response.status).toBe(BigInt(1));
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
@@ -241,6 +249,7 @@ describe('Web3Eth.sendTransaction', () => {
type: BigInt(0),
};
const response = await web3Eth.sendTransaction(transaction);
+ expect(response.events).toBeUndefined();
expect(response.type).toBe(BigInt(0));
expect(response.status).toBe(BigInt(1));
@@ -260,6 +269,7 @@ describe('Web3Eth.sendTransaction', () => {
accessList: [],
};
const response = await web3Eth.sendTransaction(transaction);
+ expect(response.events).toBeUndefined();
expect(response.type).toBe(BigInt(1));
expect(response.status).toBe(BigInt(1));
@@ -275,6 +285,7 @@ describe('Web3Eth.sendTransaction', () => {
type: BigInt(2),
};
const response = await web3Eth.sendTransaction(transaction);
+ expect(response.events).toBeUndefined();
expect(response.type).toBe(BigInt(2));
expect(response.status).toBe(BigInt(1));
@@ -291,6 +302,7 @@ describe('Web3Eth.sendTransaction', () => {
};
const response = await web3Eth.sendTransaction(transaction, DEFAULT_RETURN_FORMAT);
expect(response.type).toBe(BigInt(0));
+ expect(response.events).toBeUndefined();
expect(response.status).toBe(BigInt(1));
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
expect(minedTransactionData).toMatchObject(transaction);
@@ -304,6 +316,7 @@ describe('Web3Eth.sendTransaction', () => {
maxFeePerGas: BigInt(2500000016),
};
const response = await web3Eth.sendTransaction(transaction);
+ expect(response.events).toBeUndefined();
expect(response.type).toBe(BigInt(2));
expect(response.status).toBe(BigInt(1));
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
@@ -318,6 +331,7 @@ describe('Web3Eth.sendTransaction', () => {
maxPriorityFeePerGas: BigInt(100),
};
const response = await web3Eth.sendTransaction(transaction);
+ expect(response.events).toBeUndefined();
expect(response.type).toBe(BigInt(2));
expect(response.status).toBe(BigInt(1));
const minedTransactionData = await web3Eth.getTransaction(response.transactionHash);
@@ -379,8 +393,9 @@ describe('Web3Eth.sendTransaction', () => {
expect(typeof data.transactionIndex).toBe('bigint');
expect(data.status).toBe(BigInt(1));
expect(data.type).toBe(BigInt(0));
+ expect(data.events).toBeUndefined();
});
- expect.assertions(8);
+ expect.assertions(9);
});
it('should listen to the confirmation event', async () => {
diff --git a/packages/web3-eth-contract/test/unit/encoding.ts b/packages/web3-eth/test/unit/decoding.test.ts
similarity index 73%
rename from packages/web3-eth-contract/test/unit/encoding.ts
rename to packages/web3-eth/test/unit/decoding.test.ts
index 293e55cccfc..94627d84575 100644
--- a/packages/web3-eth-contract/test/unit/encoding.ts
+++ b/packages/web3-eth/test/unit/decoding.test.ts
@@ -15,16 +15,22 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see .
*/
import { AbiEventFragment, LogsInput } from 'web3-types';
-import { decodeEventABI } from '../../src/encoding';
-import { decodeEventABIData } from '../fixtures/encoding';
+import { decodeEventABI } from '../../src';
+import { decodeEventABIData } from '../fixtures/decoding';
-describe('encoding decoding functions', () => {
+describe('decoding functions', () => {
describe('decode', () => {
describe('decodeEventABI', () => {
it.each(decodeEventABIData)(
'%s',
(event: AbiEventFragment & { signature: string }, inputs: LogsInput, output) => {
- expect(decodeEventABI(event, inputs, [])).toBe(output);
+ expect(
+ decodeEventABI(event, inputs, [
+ { signature: event.signature } as unknown as AbiEventFragment & {
+ signature: string;
+ },
+ ]),
+ ).toStrictEqual(output);
},
);
});
diff --git a/packages/web3-eth/test/unit/send_tx_helper.test.ts b/packages/web3-eth/test/unit/send_tx_helper.test.ts
new file mode 100644
index 00000000000..55a482395b8
--- /dev/null
+++ b/packages/web3-eth/test/unit/send_tx_helper.test.ts
@@ -0,0 +1,248 @@
+/*
+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 {
+ DataFormat,
+ DEFAULT_RETURN_FORMAT,
+ EthExecutionAPI,
+ JsonRpcResponse,
+ TransactionReceipt,
+ Web3BaseWalletAccount,
+} from 'web3-types';
+import { Web3Context, Web3EventMap, Web3PromiEvent } from 'web3-core';
+import {
+ ContractExecutionError,
+ InvalidResponseError,
+ TransactionRevertInstructionError,
+} from 'web3-errors';
+import { SendTxHelper } from '../../src/utils/send_tx_helper';
+import { getTransactionError } from '../../src/utils/get_transaction_error';
+import { getTransactionGasPricing } from '../../src/utils/get_transaction_gas_pricing';
+import { getRevertReason } from '../../src/utils/get_revert_reason';
+import { trySendTransaction } from '../../src/utils/try_send_transaction';
+import { ERC20TokenAbi } from '../fixtures/erc20';
+import { SendSignedTransactionEvents, SendTransactionEvents } from '../../src';
+
+const utils = {
+ getTransactionError,
+ getRevertReason,
+ trySendTransaction,
+ getTransactionGasPricing,
+};
+jest.mock('../../src/utils/get_transaction_gas_pricing');
+jest.mock('../../src/utils/try_send_transaction');
+jest.mock('../../src/utils/get_transaction_error');
+jest.mock('../../src/utils/get_revert_reason');
+
+type PromiEvent = Web3PromiEvent<
+ TransactionReceipt,
+ SendSignedTransactionEvents | SendTransactionEvents
+>;
+const receipt = {
+ transactionHash: '0x559e12c4d679f66ff234ad2075a0953793692bdd3a9d9f12def5edc5d7cc2eec',
+ transactionIndex: BigInt(0),
+ blockNumber: BigInt(38),
+ blockHash: '0xc238b3b27edd12846afc824e4f36ebd7e6dcf35914af631f181ebc05127dd553',
+ from: '0x53a179dfe130c7b4054f7e6e7f1928777d7e7bbd',
+ to: '0xead2356c468ce5443bd7cbb2caaeb48266b7f31f',
+ cumulativeGasUsed: BigInt(47521),
+ gasUsed: BigInt(47521),
+ logs: [
+ {
+ address: '0xead2356c468ce5443bd7cbb2caaeb48266b7f31f',
+ blockHash: '0xc238b3b27edd12846afc824e4f36ebd7e6dcf35914af631f181ebc05127dd553',
+ blockNumber: BigInt(38),
+ data: '0x000000000000000000000000000000000000000000000000000000000000000a',
+ logIndex: BigInt(0),
+ removed: false,
+ topics: [
+ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
+ '0x00000000000000000000000051623651024932936d00d36a93594db5684fbbb3',
+ '0x00000000000000000000000003095dc4857bb26f3a4550c5651df8b7f6b6b1ef',
+ ],
+ transactionHash: '0x559e12c4d679f66ff234ad2075a0953793692bdd3a9d9f12def5edc5d7cc2eec',
+ transactionIndex: BigInt(0),
+ },
+ ],
+ logsBloom:
+ '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000800000000000008000000000000000000020000001000000002000000000000000000000000000200000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000',
+ status: BigInt(1),
+ effectiveGasPrice: BigInt(2506532645),
+ type: BigInt(2),
+};
+
+describe('sendTxHelper class', () => {
+ let sendTxHelper: SendTxHelper;
+ let promiEvent: Web3PromiEvent;
+ let web3Context: Web3Context;
+ beforeAll(() => {
+ web3Context = new Web3Context();
+ promiEvent = new Web3PromiEvent(resolve => {
+ resolve({} as unknown as TransactionReceipt);
+ });
+ sendTxHelper = new SendTxHelper({
+ web3Context,
+ promiEvent: promiEvent as PromiEvent,
+ options: {
+ contractAbi: ERC20TokenAbi,
+ },
+ returnFormat: DEFAULT_RETURN_FORMAT,
+ });
+ });
+ it('constructor', () => {
+ expect(sendTxHelper).toBeDefined();
+ // @ts-expect-error get private property
+ expect(sendTxHelper.promiEvent).toBe(promiEvent);
+ // @ts-expect-error get private property
+ expect(sendTxHelper.web3Context).toBe(web3Context);
+ // @ts-expect-error get private property
+ expect(sendTxHelper.returnFormat).toBe(DEFAULT_RETURN_FORMAT);
+ });
+ it('getReceiptWithEvents', () => {
+ const res = sendTxHelper.getReceiptWithEvents(receipt as unknown as TransactionReceipt);
+ expect(res?.events?.Transfer.address).toBeDefined();
+ });
+ it('emit sending', async () => {
+ const f = jest.fn();
+ await promiEvent.on('sending', f);
+ sendTxHelper.emitSending(receipt);
+ expect(f).toHaveBeenCalledWith(receipt);
+ promiEvent.off('sending', f);
+ });
+ it('emit emitSent', async () => {
+ const f = jest.fn();
+ await promiEvent.on('sent', f);
+ sendTxHelper.emitSent(receipt);
+ expect(f).toHaveBeenCalledWith(receipt);
+ promiEvent.off('sent', f);
+ });
+ it('emit emitTransactionHash', async () => {
+ const f = jest.fn();
+ await promiEvent.on('transactionHash', f);
+ sendTxHelper.emitTransactionHash(receipt.transactionHash as string & Uint8Array);
+ expect(f).toHaveBeenCalledWith(receipt.transactionHash);
+ promiEvent.off('transactionHash', f);
+ });
+ it('emit emitReceipt', async () => {
+ const f = jest.fn();
+ await promiEvent.on('receipt', f);
+ sendTxHelper.emitReceipt(receipt as TransactionReceipt);
+ expect(f).toHaveBeenCalledWith(receipt);
+ promiEvent.off('receipt', f);
+ });
+ it('emit handleError', async () => {
+ const f = jest.fn();
+ await promiEvent.on('error', f);
+ const error = new InvalidResponseError({} as JsonRpcResponse);
+ await sendTxHelper.handleError({ error, tx: receipt });
+ expect(f).toHaveBeenCalledWith(error);
+ promiEvent.off('error', f);
+ });
+ it('emit handleError with handleRevert', async () => {
+ const error = new ContractExecutionError({ code: 1, message: 'error' });
+ web3Context.handleRevert = true;
+ jest.spyOn(utils, 'getTransactionError').mockResolvedValue(
+ error as unknown as TransactionRevertInstructionError,
+ );
+ await sendTxHelper.handleError({ error, tx: receipt });
+ expect(utils.getTransactionError).toHaveBeenCalled();
+ });
+ it('emit handleResolve', async () => {
+ const f = jest.fn();
+ const error = new TransactionRevertInstructionError('error');
+ jest.spyOn(utils, 'getTransactionError').mockResolvedValue(error);
+ await promiEvent.on('error', f);
+
+ await expect(async () => {
+ await sendTxHelper.handleResolve({
+ receipt: { ...receipt, status: BigInt(0) } as TransactionReceipt,
+ tx: receipt,
+ });
+ expect(utils.getTransactionError).toHaveBeenCalled();
+ expect(f).toHaveBeenCalledWith(error);
+ promiEvent.off('error', f);
+ }).rejects.toThrow();
+ });
+ it('emit checkRevertBeforeSending', async () => {
+ const _sendTxHelper = new SendTxHelper({
+ web3Context,
+ promiEvent: promiEvent as PromiEvent,
+ options: {
+ checkRevertBeforeSending: true,
+ },
+ returnFormat: DEFAULT_RETURN_FORMAT,
+ });
+ const error = new TransactionRevertInstructionError('error');
+ jest.spyOn(utils, 'getRevertReason').mockResolvedValue(error);
+ await expect(_sendTxHelper.checkRevertBeforeSending(receipt)).rejects.toThrow();
+ expect(utils.getRevertReason).toHaveBeenCalled();
+ });
+ it('emit handleResolve with transactionResolver', async () => {
+ const f = jest.fn();
+
+ const _sendTxHelper = new SendTxHelper({
+ web3Context,
+ promiEvent: promiEvent as PromiEvent,
+ options: {
+ transactionResolver: f,
+ },
+ returnFormat: DEFAULT_RETURN_FORMAT,
+ });
+
+ await _sendTxHelper.handleResolve({ receipt: receipt as TransactionReceipt, tx: receipt });
+ expect(f).toHaveBeenCalledWith(receipt);
+ });
+ it('emit populateGasPrice', async () => {
+ const _sendTxHelper = new SendTxHelper({
+ web3Context,
+ promiEvent: promiEvent as PromiEvent,
+ options: {
+ ignoreGasPricing: false,
+ },
+ returnFormat: DEFAULT_RETURN_FORMAT,
+ });
+ const receiptWithoutGas = {
+ ...receipt,
+ gasPrice: undefined,
+ maxPriorityFeePerGas: undefined,
+ maxFeePerGas: undefined,
+ };
+ const populatedReceipt = { ...receiptWithoutGas, gasPrice: 1 };
+ jest.spyOn(utils, 'getTransactionGasPricing').mockResolvedValue(populatedReceipt);
+ const result = await _sendTxHelper.populateGasPrice({
+ transaction: receiptWithoutGas,
+ transactionFormatted: receiptWithoutGas,
+ });
+ expect(result).toStrictEqual(populatedReceipt);
+ expect(utils.getTransactionGasPricing).toHaveBeenCalled();
+ });
+ it('emit signAndSend', async () => {
+ jest.spyOn(utils, 'trySendTransaction').mockResolvedValue('success');
+ const wallet = {
+ signTransaction: jest.fn(() => ({
+ transactionHash: receipt.transactionHash,
+ rawTransaction: receipt,
+ })),
+ };
+ const result = await sendTxHelper.signAndSend({
+ tx: receipt,
+ wallet: wallet as unknown as Web3BaseWalletAccount,
+ });
+ expect(result).toBe('success');
+ expect(utils.trySendTransaction).toHaveBeenCalled();
+ expect(wallet.signTransaction).toHaveBeenCalledWith(receipt);
+ });
+});
diff --git a/packages/web3-types/CHANGELOG.md b/packages/web3-types/CHANGELOG.md
index f85baa353bc..e0f82088f8e 100644
--- a/packages/web3-types/CHANGELOG.md
+++ b/packages/web3-types/CHANGELOG.md
@@ -164,4 +164,8 @@ Documentation:
- add `asEIP1193Provider` to `Web3BaseProvider` so every inherited class can have the returned value of `request` method, fully compatible with EIP-1193. (#6407)
-## [Unreleased]
\ No newline at end of file
+## [Unreleased]
+
+### Added
+
+- Interface `EventLog` was added. (#6410)
diff --git a/packages/web3-types/src/eth_contract_types.ts b/packages/web3-types/src/eth_contract_types.ts
index 6c4dd374869..15d23b36470 100644
--- a/packages/web3-types/src/eth_contract_types.ts
+++ b/packages/web3-types/src/eth_contract_types.ts
@@ -19,6 +19,7 @@ import { Address, Uint } from './eth_types.js';
import { SupportedProviders } from './web3_base_provider.js';
import { Bytes, HexString } from './primitives_types.js';
import { EthExecutionAPI } from './apis/eth_execution_api.js';
+import { AbiFragment, ContractAbi } from './eth_abi_types.js';
export interface ContractInitOptions {
/**
@@ -80,3 +81,78 @@ export interface PayableCallOptions extends NonPayableCallOptions {
*/
value?: string;
}
+
+export type ContractAbiWithSignature = ReadonlyArray;
+export interface ContractOptions {
+ /**
+ * The maximum gas provided for a transaction (gas limit).
+ */
+ readonly gas?: Uint;
+ /**
+ * The gas price in wei to use for transactions.
+ */
+ readonly gasPrice?: Uint;
+ /**
+ * The address transactions should be made from.
+ */
+ readonly from?: Address;
+ /**
+ * 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.
+ *
+ * Re-setting this will regenerate the methods and events of the contract instance.
+ *
+ * ```ts
+ * myContract.options.jsonInterface;
+ * > [{
+ * "type":"function",
+ * "name":"foo",
+ * "inputs": [{"name":"a","type":"uint256"}],
+ * "outputs": [{"name":"b","type":"address"}],
+ * "signature": "0x...",
+ * },{
+ * "type":"event",
+ * "name":"Event",
+ * "inputs": [{"name":"a","type":"uint256","indexed":true},{"name":"b","type":"bytes32","indexed":false}],
+ * "signature": "0x...",
+ * }]
+ *
+ * // Set a new ABI interface
+ * // Note: the "signature" of every function and event's ABI is not needed to be provided when assigning.
+ * // It will be calculated and set automatically inside the setter.
+ * myContract.options.jsonInterface = [...];
+ * ```
+ */
+ get jsonInterface(): ContractAbiWithSignature;
+ set jsonInterface(value: ContractAbi);
+
+ /**
+ * The address used for this contract instance. All transactions generated by web3.js from this contract will contain this address as the `to`.
+ *
+ * The address will be stored in lowercase.
+ *
+ * ```ts
+ * myContract.options.address;
+ * > '0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae'
+ *
+ * // set a new address
+ * myContract.options.address = '0x1234FFDD...';
+ * ```
+ */
+ address?: Address; // All transactions generated by web3.js from this contract will contain this address as the "to".
+ /**
+ * The max priority fee per gas to use for transactions.
+ */
+ maxPriorityFeePerGas?: Uint;
+ /**
+ * The max fee per gas to use for transactions.
+ */
+ maxFeePerGas?: Uint;
+}
diff --git a/packages/web3-types/src/eth_types.ts b/packages/web3-types/src/eth_types.ts
index f1fa62dd743..8c59752e20a 100644
--- a/packages/web3-types/src/eth_types.ts
+++ b/packages/web3-types/src/eth_types.ts
@@ -312,6 +312,23 @@ export interface LogBase {
export interface Log extends LogBase {
readonly id?: string;
}
+
+export interface EventLog {
+ readonly event: string;
+ readonly id?: string;
+ readonly logIndex?: bigint | number | string;
+ readonly transactionIndex?: bigint | number | string;
+ readonly transactionHash?: HexString32Bytes;
+ readonly blockHash?: HexString32Bytes;
+ readonly blockNumber?: bigint | number | string;
+ readonly address: string;
+ readonly topics: HexString[];
+ readonly data: HexString;
+ readonly raw?: { data: string; topics: unknown[] };
+ readonly returnValues: Record;
+ readonly signature?: HexString;
+}
+
export interface TransactionReceiptBase {
readonly transactionHash: hashByteType;
readonly transactionIndex: numberType;
@@ -328,6 +345,7 @@ export interface TransactionReceiptBase;