From 2ac0b12b34ede63aac3dc1d7b698b61dfd42a5ee Mon Sep 17 00:00:00 2001 From: Will Cory Date: Sun, 24 Sep 2023 02:41:17 -0700 Subject: [PATCH] :sparkles: feat(ethers): Make events typesafe (#479) ## Description Make ethers events typesafe ## Testing Explain the quality checks that have been done on the code changes ## Additional Information - [ ] I read the [contributing docs](../docs/contributing.md) (if this is your first contribution) Your ENS/address: Co-authored-by: Will Cory --- .changeset/cyan-trainers-change.md | 5 +++++ ethers/src/Contract.spec.ts | 20 ------------------ ethers/src/TypesafeEthersContract.ts | 31 ++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 .changeset/cyan-trainers-change.md diff --git a/.changeset/cyan-trainers-change.md b/.changeset/cyan-trainers-change.md new file mode 100644 index 0000000000..cd03aa5139 --- /dev/null +++ b/.changeset/cyan-trainers-change.md @@ -0,0 +1,5 @@ +--- +"@evmts/ethers": minor +--- + +Add typesafe event inputs. The input type will have autocomplete but still is widened to accept the ethers type. The return type is extremely difficult to override to being generic diff --git a/ethers/src/Contract.spec.ts b/ethers/src/Contract.spec.ts index c4fd9aa0aa..97cb7b21ca 100644 --- a/ethers/src/Contract.spec.ts +++ b/ethers/src/Contract.spec.ts @@ -289,24 +289,4 @@ describe('ethers.Contract', () => { await c.balanceOf('0x32307adfFE088e383AFAa721b06436aDaBA47DBE'), ).toMatchInlineSnapshot('0n') }) - - test('should work with custom address with chainId supplied even though the chainId is unnecessary', async () => { - const c = new Contract(addresses[420], abi, provider) - expect(c).toBeInstanceOf(Contract) - expect(await c.name({ blockTag: 12865720 })).toMatchInlineSnapshot( - '"OptimismUselessToken-1"', - ) - expect(await c.symbol({ blockTag: 12865720 })).toMatchInlineSnapshot( - '"OUT-1"', - ) - expect(await c.decimals({ blockTag: 12865720 })).toMatchInlineSnapshot( - '18n', - ) - expect(await c.totalSupply({ blockTag: 12865720 })).toMatchInlineSnapshot( - '71000000000000000000000n', - ) - expect( - await c.balanceOf('0x32307adfFE088e383AFAa721b06436aDaBA47DBE'), - ).toMatchInlineSnapshot('0n') - }) }) diff --git a/ethers/src/TypesafeEthersContract.ts b/ethers/src/TypesafeEthersContract.ts index 788deaa1c2..f616ec3e95 100644 --- a/ethers/src/TypesafeEthersContract.ts +++ b/ethers/src/TypesafeEthersContract.ts @@ -2,11 +2,19 @@ import type { BaseContractMethod } from './BaseContractMethod' import type { Abi, AbiParametersToPrimitiveTypes, + ExtractAbiEvent, + ExtractAbiEventNames, ExtractAbiFunction, ExtractAbiFunctionNames, } from 'abitype' -import type { ContractTransactionResponse } from 'ethers' -import type { BaseContract } from 'ethers' +import type { Log } from 'ethers' +import type { EventLog } from 'ethers' +import type { BlockTag } from 'ethers' +import type { + BaseContract, + ContractEventName, + ContractTransactionResponse, +} from 'ethers' export type TypesafeEthersContract = BaseContract & { // readonly methods @@ -43,4 +51,23 @@ export type TypesafeEthersContract = BaseContract & { >[0], ContractTransactionResponse > +} & { + // events + queryFilter: < + TContractEventName extends + | Omit> + | ExtractAbiEventNames, + >( + event: TContractEventName, + fromBlock?: BlockTag, + toBlock?: BlockTag, + // TODO this return type does not work + // this is extremely difficult to override the return type into being generic + ) => Promise< + Array< + TContractEventName extends ExtractAbiEventNames + ? ExtractAbiEvent + : EventLog | Log + > + > }