Skip to content

Commit

Permalink
Add events to receipt object (#6410)
Browse files Browse the repository at this point in the history
* refactor send transaction and add events to receipt object

* fix unit tests

* fix

* move type

* fix exports

* fix integration test

* add change logs

* add decoding test

* cover send_tx_helper

* add receipt events checks into integration tests

* update latest version. changelog sync

* add change logs

* add values check to test
  • Loading branch information
avkos committed Sep 21, 2023
1 parent 66ddb7e commit 171b413
Show file tree
Hide file tree
Showing 35 changed files with 1,642 additions and 556 deletions.
25 changes: 23 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
6 changes: 5 additions & 1 deletion packages/web3-eth-contract/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
## [Unreleased]

### Changed

- The `events` property was added to the `receipt` object (#6410)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
This file is part of web3.js.
web3.js is free software: you can redistribute it and/or modify
Expand All @@ -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 <http://www.gnu.org/licenses/>.
*/

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';
31 changes: 21 additions & 10 deletions packages/web3-eth-contract/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ import {
call,
estimateGas,
getLogs,
NewHeadsSubscription,
sendTransaction,
decodeEventABI,
NewHeadsSubscription,
ALL_EVENTS,
ALL_EVENTS_ABI,
SendTransactionEvents,
} from 'web3-eth';
import {
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -707,24 +709,29 @@ export class Contract<Abi extends ContractAbi>
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents<ReturnFormat extends DataFormat = typeof DEFAULT_RETURN_FORMAT>(
eventName: keyof ContractEvents<Abi> | 'allEvents',
eventName: keyof ContractEvents<Abi> | 'allEvents' | 'ALLEVENTS',
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents<ReturnFormat extends DataFormat = typeof DEFAULT_RETURN_FORMAT>(
filter: Omit<Filter, 'address'>,
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents<ReturnFormat extends DataFormat = typeof DEFAULT_RETURN_FORMAT>(
eventName: keyof ContractEvents<Abi> | 'allEvents',
eventName: keyof ContractEvents<Abi> | 'allEvents' | 'ALLEVENTS',
filter: Omit<Filter, 'address'>,
returnFormat?: ReturnFormat,
): Promise<(string | EventLog)[]>;
public async getPastEvents<ReturnFormat extends DataFormat = typeof DEFAULT_RETURN_FORMAT>(
param1?: keyof ContractEvents<Abi> | 'allEvents' | Omit<Filter, 'address'> | ReturnFormat,
param1?:
| keyof ContractEvents<Abi>
| 'allEvents'
| 'ALLEVENTS'
| Omit<Filter, 'address'>
| ReturnFormat,
param2?: Omit<Filter, 'address'> | 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
Expand All @@ -751,11 +758,13 @@ export class Contract<Abi extends ContractAbi>
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'
Expand Down Expand Up @@ -1076,6 +1085,7 @@ export class Contract<Abi extends ContractAbi>
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
Expand Down Expand Up @@ -1117,6 +1127,7 @@ export class Contract<Abi extends ContractAbi>
newContract.options.address = receipt.contractAddress;
return newContract;
},
contractAbi: this._jsonInterface,
// TODO Should make this configurable by the user
checkRevertBeforeSending: false,
});
Expand Down
77 changes: 5 additions & 72 deletions packages/web3-eth-contract/src/encoding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<T> = { -readonly [P in keyof T]: T[P] };
export const encodeEventABI = (
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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[],
Expand Down
15 changes: 10 additions & 5 deletions packages/web3-eth-contract/src/log_subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ You should have received a copy of the GNU Lesser General Public License
along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

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.
Expand Down
Loading

0 comments on commit 171b413

Please sign in to comment.