TypeChain
TypeChain copied to clipboard
ethers-v6: wrong type generated for listening to contract events
I've generated the types for an ERC20 contract with ethers-v6. I would like to listen to the transfer events, to that end I call
token.on(token.filters.Transfer(), async (...args) => {
const lastArg = args[args.length - 1];
console.log(lastArg)
// do something with it
}
The generated types claim lastArg to be of type:
lastArg: TypedEventLog<TypedContractEvent<TransferEvent.InputTuple, TransferEvent.OutputTuple, TransferEvent.OutputObject>> | undefined | string | bigint
However, the console.log gives me the following output:
ContractEventPayload {
filter: PreparedTopicFilter {
fragment: EventFragment {
type: 'event',
inputs: [Array],
name: 'Transfer',
anonymous: false
}
},
emitter: Contract {
target: '0x...',
interface: Interface {
fragments: [Array],
deploy: [ConstructorFragment],
fallback: null,
receive: false
},
runner: Wallet {
provider: [InfuraProvider],
address: '0x...'
},
filters: {},
fallback: null,
[Symbol(_ethersInternal_contract)]: {}
},
log: EventLog {
provider: InfuraProvider {
projectId: '...',
projectSecret: ...
},
transactionHash: '0x...',
blockHash: '0x...',
blockNumber: ...,
removed: false,
address: '0x...',
data: '0x...,
topics: [
'0x...',
'0x...',
'0x...'
],
index: 12,
transactionIndex: 6,
interface: Interface {
fragments: [Array],
deploy: [ConstructorFragment],
fallback: null,
receive: false
},
fragment: EventFragment {
type: 'event',
inputs: [Array],
name: 'Transfer',
anonymous: false
},
args: Result(3) [
'0x...',
'0x...',
10000n
]
},
args: Result(3) [
'0x...',
'0x...',
10000n
],
fragment: EventFragment {
type: 'event',
inputs: [ [ParamType], [ParamType], [ParamType] ],
name: 'Transfer',
anonymous: false
}
}
The TypedEventLog<...
object is actually found under lastArg.log
instead of lastArg
itself being of type TypedEventLog<...
Checking the ethers documentation under "Listening to Events" it says that
There is always one additional parameter passed to a listener, which is an EventPayload, which includes more information about the event including the filter and a method to remove that listener.
Which seems to line up with the behaviour I am observing
Yes, I can confirm that the types are incorrect. The ...args
array actually just contains a single element, which is the one you have logged.
@kliyer-ai Why are the types incorrect though? Is it a bug in typechain? Or did I make some sort of mistake in using it?
I think this is a bug in typechain.
When i was constructing my listeners without typechain using
const VAULT_EVENTS = [
'event Deposit(address account, uint256 amount, uint256 amountStaked)',
'event Withdraw(address account, uint256 amount)',
];
console.log(`Setting up ${name}: ${address} listener`);
const contract = new Contract(address, VAULT_EVENTS, provider);
contract.on(
'Deposit',
async (
account: string,
amount: number,
amountStaked: number,
event: ContractEventPayload
) => {
const template = `**${name}**: \`Deposit\` ${formatUnits(
amount,
18
)} $FOO into \`${account}\` for (${formatUnits(
amountStaked,
18
)} total`;
await notify({
text: template,
txid: event.log.transactionHash,
});
}
);
The listener last arg is ethers.ContractEventPayload
so i can access event.log.transactionHash
.
When using generated Contract__factory().on(contract.filters.Deposit, ...)
I can confirm that
- (
account
,amount
,amountStaked
) is parsed correctly - the last arg
event
is (incorrectly) typed as you describe, so when you accessevent.transactionHash
it isnull
.
Not sure how exactly to fix, but imho the generated typechain/common.ts
export type TypedListener<TCEvent extends TypedContractEvent> = (
...listenerArg: [
...__TypechainAOutputTuple<TCEvent>,
TypedEventLog<TCEvent>
...undefined[]
]
) => void;
should just type the last arg as
import { ContractEventPayload } from 'ethers';
export type TypedListener<TCEvent extends TypedContractEvent> = (
...listenerArg: [
...__TypechainAOutputTuple<TCEvent>,
ContractEventPayload, // this
...undefined[]
]
) => void;
this is still not fixed, right?
Please, can the PR that fix this issue be merged?