From b1ee64c5ea440e7d4be26676301f742d3cb6e03e Mon Sep 17 00:00:00 2001 From: "moxey.eth" Date: Tue, 14 May 2024 13:38:39 +1000 Subject: [PATCH] feat: useTransactionReceipt --- ...ipt.ts => useTransactionReceipt.test-d.ts} | 0 .../vue/src/useTransactionReceipt.test-d.ts | 41 ++++ packages/test/src/exports/vue.ts | 2 +- .../src/composables/useAccountEffect.test.ts | 4 +- .../vue/src/composables/useBalance.test.ts | 10 +- .../vue/src/composables/useEnsAddress.test.ts | 2 +- .../vue/src/composables/useEnsAvatar.test.ts | 2 +- .../src/composables/useEstimateGas.test.ts | 4 +- .../src/composables/useReadContract.test.ts | 4 +- .../vue/src/composables/useReconnect.test.ts | 6 +- .../composables/useSendTransaction.test.ts | 2 +- .../src/composables/useSignMessage.test.ts | 4 +- .../src/composables/useSignTypedData.test.ts | 4 +- .../composables/useSimulateContract.test.ts | 2 +- .../src/composables/useSwitchAccount.test.ts | 4 +- .../src/composables/useSwitchChain.test.ts | 4 +- .../src/composables/useTransaction.test.ts | 2 +- .../useTransactionReceipt.test-d.ts | 14 ++ .../composables/useTransactionReceipt.test.ts | 208 ++++++++++++++++++ .../src/composables/useTransactionReceipt.ts | 85 +++++++ .../useWaitForTransactionReceipt.test.ts | 2 +- .../src/composables/useWriteContract.test.ts | 2 +- packages/vue/src/exports/index.ts | 6 + site/.vitepress/sidebar.ts | 4 + .../api/composables/useTransactionReceipt.md | 141 ++++++++++++ 25 files changed, 529 insertions(+), 30 deletions(-) rename packages/register-tests/react/src/{useTransactionReceipt.ts => useTransactionReceipt.test-d.ts} (100%) create mode 100644 packages/register-tests/vue/src/useTransactionReceipt.test-d.ts create mode 100644 packages/vue/src/composables/useTransactionReceipt.test-d.ts create mode 100644 packages/vue/src/composables/useTransactionReceipt.test.ts create mode 100644 packages/vue/src/composables/useTransactionReceipt.ts create mode 100644 site/vue/api/composables/useTransactionReceipt.md diff --git a/packages/register-tests/react/src/useTransactionReceipt.ts b/packages/register-tests/react/src/useTransactionReceipt.test-d.ts similarity index 100% rename from packages/register-tests/react/src/useTransactionReceipt.ts rename to packages/register-tests/react/src/useTransactionReceipt.test-d.ts diff --git a/packages/register-tests/vue/src/useTransactionReceipt.test-d.ts b/packages/register-tests/vue/src/useTransactionReceipt.test-d.ts new file mode 100644 index 0000000000..21c0cb3b3f --- /dev/null +++ b/packages/register-tests/vue/src/useTransactionReceipt.test-d.ts @@ -0,0 +1,41 @@ +import { config } from '@wagmi/test' +import { useTransactionReceipt } from '@wagmi/vue' +import { zkSync } from '@wagmi/vue/chains' +import { type ZkSyncL2ToL1Log, type ZkSyncLog } from 'viem/zksync' +import { expectTypeOf, test } from 'vitest' + +test('chain formatters', () => { + const result = useTransactionReceipt() + + if (result.data?.value?.chainId === zkSync.id) { + expectTypeOf(result.data.value.l1BatchNumber).toEqualTypeOf() + expectTypeOf(result.data.value.l1BatchTxIndex).toEqualTypeOf< + bigint | null + >() + expectTypeOf(result.data.value.logs).toEqualTypeOf() + expectTypeOf(result.data.value.l2ToL1Logs).toEqualTypeOf< + ZkSyncL2ToL1Log[] + >() + } + + const result2 = useTransactionReceipt({ chainId: zkSync.id }) + if (result2.data.value) { + expectTypeOf(result2.data.value.l1BatchNumber).toEqualTypeOf< + bigint | null + >() + expectTypeOf(result2.data.value.l1BatchTxIndex).toEqualTypeOf< + bigint | null + >() + expectTypeOf(result2.data.value.logs).toEqualTypeOf() + expectTypeOf(result2.data.value.l2ToL1Logs).toEqualTypeOf< + ZkSyncL2ToL1Log[] + >() + } +}) + +test('parameters: config', async () => { + const result = useTransactionReceipt({ config }) + + if (result.data && 'l1BatchNumber' in result.data) + expectTypeOf(result.data.l1BatchNumber).toEqualTypeOf() +}) diff --git a/packages/test/src/exports/vue.ts b/packages/test/src/exports/vue.ts index 779f0c3a21..ac49b17a31 100644 --- a/packages/test/src/exports/vue.ts +++ b/packages/test/src/exports/vue.ts @@ -42,7 +42,7 @@ export type WaitForOptions = { export function waitFor( ref: ref, - predicate: (value: ref['value']) => boolean, + predicate: (value: ref['value']) => boolean = (value) => value, options: WaitForOptions = {}, ) { const { timeout = 10_000 } = options diff --git a/packages/vue/src/composables/useAccountEffect.test.ts b/packages/vue/src/composables/useAccountEffect.test.ts index 4d508b6b62..10ed7a3e37 100644 --- a/packages/vue/src/composables/useAccountEffect.test.ts +++ b/packages/vue/src/composables/useAccountEffect.test.ts @@ -23,13 +23,13 @@ test('behavior: connect and disconnect called once', async () => { connect.connect({ connector: connect.connectors[0]!, }) - await waitFor(connect.isSuccess, (isSuccess) => isSuccess) + await waitFor(connect.isSuccess) connect.connect({ connector: connect.connectors[0]!, }) disconnect.disconnect() - await waitFor(disconnect.isSuccess, (isSuccess) => isSuccess) + await waitFor(disconnect.isSuccess) disconnect.disconnect() expect(onConnect).toBeCalledTimes(1) diff --git a/packages/vue/src/composables/useBalance.test.ts b/packages/vue/src/composables/useBalance.test.ts index c609414cc9..b6967d70f9 100644 --- a/packages/vue/src/composables/useBalance.test.ts +++ b/packages/vue/src/composables/useBalance.test.ts @@ -18,7 +18,7 @@ beforeEach(async () => { test('default', async () => { const [query] = renderComposable(() => useBalance({ address })) - await waitFor(query.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(query.isSuccess) expect(query.data.value).toMatchInlineSnapshot(` { @@ -35,7 +35,7 @@ test('parameters: chainId', async () => { useBalance({ address, chainId: chain.mainnet2.id }), ) - await waitFor(query.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(query.isSuccess) expect(query.data.value).toMatchInlineSnapshot(` { @@ -55,7 +55,7 @@ test('parameters: token', async () => { }), ) - await waitFor(query.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(query.isSuccess) expect(query.data.value).toMatchInlineSnapshot(` { @@ -76,7 +76,7 @@ test('parameters: unit', async () => { }), ) - await waitFor(query.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(query.isSuccess) expect(query.data.value).toMatchInlineSnapshot(` { @@ -98,7 +98,7 @@ test('behavior: address: undefined -> defined', async () => { address.value = accounts[0] - await waitFor(query.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(query.isSuccess) expect(query.data.value).toMatchInlineSnapshot(` { diff --git a/packages/vue/src/composables/useEnsAddress.test.ts b/packages/vue/src/composables/useEnsAddress.test.ts index d5f18bb4c1..01d35769b7 100644 --- a/packages/vue/src/composables/useEnsAddress.test.ts +++ b/packages/vue/src/composables/useEnsAddress.test.ts @@ -11,7 +11,7 @@ test('default', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) expect(deepUnref(result)).toMatchInlineSnapshot(` { diff --git a/packages/vue/src/composables/useEnsAvatar.test.ts b/packages/vue/src/composables/useEnsAvatar.test.ts index af6a2dcfa1..ab024c89b5 100644 --- a/packages/vue/src/composables/useEnsAvatar.test.ts +++ b/packages/vue/src/composables/useEnsAvatar.test.ts @@ -11,7 +11,7 @@ test('default', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) expect(deepUnref(result)).toMatchInlineSnapshot(` { diff --git a/packages/vue/src/composables/useEstimateGas.test.ts b/packages/vue/src/composables/useEstimateGas.test.ts index 184646a26f..f8212f11da 100644 --- a/packages/vue/src/composables/useEstimateGas.test.ts +++ b/packages/vue/src/composables/useEstimateGas.test.ts @@ -16,7 +16,7 @@ test('default', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) expect(deepUnref(result)).toMatchInlineSnapshot(` { @@ -74,7 +74,7 @@ test('behavior: address: undefined -> defined', async () => { address.value = accounts[0] - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) expect(deepUnref(result)).toMatchInlineSnapshot(` { diff --git a/packages/vue/src/composables/useReadContract.test.ts b/packages/vue/src/composables/useReadContract.test.ts index 1f6dc7d1ee..6ca7a049f1 100644 --- a/packages/vue/src/composables/useReadContract.test.ts +++ b/packages/vue/src/composables/useReadContract.test.ts @@ -15,7 +15,7 @@ test('default', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(result.isSuccess) expect(result.data.value).toBe(4n) expect(result.queryKey).toMatchInlineSnapshot(` @@ -44,7 +44,7 @@ test('parameters: chainId', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(result.isSuccess) expect(result.data.value).toBe(4n) expect(result.queryKey).toMatchInlineSnapshot(` diff --git a/packages/vue/src/composables/useReconnect.test.ts b/packages/vue/src/composables/useReconnect.test.ts index 92979660ae..49cf7f73e5 100644 --- a/packages/vue/src/composables/useReconnect.test.ts +++ b/packages/vue/src/composables/useReconnect.test.ts @@ -23,7 +23,7 @@ test('default', async () => { const [reconnect] = renderComposable(() => useReconnect()) reconnect.reconnect() - await waitFor(reconnect.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(reconnect.isSuccess) expect(reconnect.data.value).toStrictEqual([]) }) @@ -34,7 +34,7 @@ test('parameters: connectors (Connector)', async () => { const [reconnect] = renderComposable(() => useReconnect()) reconnect.reconnect({ connectors: [connector] }) - await waitFor(reconnect.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(reconnect.isSuccess) expect(reconnect.data.value).toMatchObject( expect.arrayContaining([ @@ -56,7 +56,7 @@ test('parameters: connectors (CreateConnectorFn)', async () => { const [reconnect] = renderComposable(() => useReconnect()) reconnect.reconnect({ connectors: [connector] }) - await waitFor(reconnect.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(reconnect.isSuccess) expect(reconnect.data.value).toMatchObject( expect.arrayContaining([ diff --git a/packages/vue/src/composables/useSendTransaction.test.ts b/packages/vue/src/composables/useSendTransaction.test.ts index 0aff13c5e8..ae069766ee 100644 --- a/packages/vue/src/composables/useSendTransaction.test.ts +++ b/packages/vue/src/composables/useSendTransaction.test.ts @@ -17,7 +17,7 @@ test('default', async () => { to: '0xd2135CfB216b74109775236E36d4b433F1DF507B', value: parseEther('0.01'), }) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) expect(result.data.value).toMatch(transactionHashRegex) diff --git a/packages/vue/src/composables/useSignMessage.test.ts b/packages/vue/src/composables/useSignMessage.test.ts index 126eb04a1e..a00691fb7f 100644 --- a/packages/vue/src/composables/useSignMessage.test.ts +++ b/packages/vue/src/composables/useSignMessage.test.ts @@ -15,7 +15,7 @@ test('default', async () => { const [result] = renderComposable(() => useSignMessage()) result.signMessage({ message: 'foo bar baz' }) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) await expect( recoverMessageAddress({ @@ -32,7 +32,7 @@ test('behavior: local account', async () => { const account = privateKeyToAccount(privateKey) result.signMessage({ account, message: 'foo bar baz' }) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) await expect( recoverMessageAddress({ diff --git a/packages/vue/src/composables/useSignTypedData.test.ts b/packages/vue/src/composables/useSignTypedData.test.ts index 6f5634f4c8..e3636d21eb 100644 --- a/packages/vue/src/composables/useSignTypedData.test.ts +++ b/packages/vue/src/composables/useSignTypedData.test.ts @@ -19,7 +19,7 @@ test('default', async () => { primaryType: 'Mail', message: typedData.basic.message, }) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) await expect( recoverTypedDataAddress({ @@ -43,7 +43,7 @@ test('behavior: local account', async () => { primaryType: 'Mail', message: typedData.basic.message, }) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) await expect( recoverTypedDataAddress({ diff --git a/packages/vue/src/composables/useSimulateContract.test.ts b/packages/vue/src/composables/useSimulateContract.test.ts index 8b8cd3a153..b93b829b65 100644 --- a/packages/vue/src/composables/useSimulateContract.test.ts +++ b/packages/vue/src/composables/useSimulateContract.test.ts @@ -18,7 +18,7 @@ test('default', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) expect(result.data.value).toMatchInlineSnapshot(` { diff --git a/packages/vue/src/composables/useSwitchAccount.test.ts b/packages/vue/src/composables/useSwitchAccount.test.ts index 242e6b2304..aade28e3d2 100644 --- a/packages/vue/src/composables/useSwitchAccount.test.ts +++ b/packages/vue/src/composables/useSwitchAccount.test.ts @@ -24,14 +24,14 @@ test('default', async () => { expect(address1).toBeDefined() switchAccount.switchAccount({ connector: connector2 }) - await waitFor(switchAccount.isSuccess, (isSuccess) => isSuccess) + await waitFor(switchAccount.isSuccess) const address2 = account.address.value expect(address2).toBeDefined() expect(address1).not.toBe(address2) switchAccount.switchAccount({ connector: connector1 }) - await waitFor(switchAccount.isSuccess, (isSuccess) => isSuccess) + await waitFor(switchAccount.isSuccess) const address3 = account.address.value expect(address3).toBeDefined() diff --git a/packages/vue/src/composables/useSwitchChain.test.ts b/packages/vue/src/composables/useSwitchChain.test.ts index 6bcfeeea86..12e7c21c2e 100644 --- a/packages/vue/src/composables/useSwitchChain.test.ts +++ b/packages/vue/src/composables/useSwitchChain.test.ts @@ -18,14 +18,14 @@ test('default', async () => { expect(chainId1).toBeDefined() switchChain.switchChain({ chainId: chain.mainnet2.id }) - await waitFor(switchChain.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(switchChain.isSuccess) const chainId2 = account.chainId.value expect(chainId2).toBeDefined() expect(chainId1).not.toBe(chainId2) switchChain.switchChain({ chainId: chain.mainnet.id }) - await waitFor(switchChain.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(switchChain.isSuccess) const chainId3 = account.chainId.value expect(chainId3).toBeDefined() diff --git a/packages/vue/src/composables/useTransaction.test.ts b/packages/vue/src/composables/useTransaction.test.ts index 9b5de407e1..06659958f2 100644 --- a/packages/vue/src/composables/useTransaction.test.ts +++ b/packages/vue/src/composables/useTransaction.test.ts @@ -11,7 +11,7 @@ test('default', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => isSuccess) + await waitFor(result.isSuccess) expect(deepUnref(result)).toMatchInlineSnapshot(` { diff --git a/packages/vue/src/composables/useTransactionReceipt.test-d.ts b/packages/vue/src/composables/useTransactionReceipt.test-d.ts new file mode 100644 index 0000000000..180d8354d8 --- /dev/null +++ b/packages/vue/src/composables/useTransactionReceipt.test-d.ts @@ -0,0 +1,14 @@ +import { expectTypeOf, test } from 'vitest' + +import { useTransactionReceipt } from './useTransactionReceipt.js' + +test('select data', () => { + const result = useTransactionReceipt({ + query: { + select(data) { + return data?.blockNumber + }, + }, + }) + expectTypeOf(result.data.value).toEqualTypeOf() +}) diff --git a/packages/vue/src/composables/useTransactionReceipt.test.ts b/packages/vue/src/composables/useTransactionReceipt.test.ts new file mode 100644 index 0000000000..0092671427 --- /dev/null +++ b/packages/vue/src/composables/useTransactionReceipt.test.ts @@ -0,0 +1,208 @@ +import { chain, wait } from '@wagmi/test' +import { renderComposable, waitFor } from '@wagmi/test/vue' +import { expect, test } from 'vitest' +import { ref } from 'vue' +import { deepUnref } from '../utils/cloneDeep.js' +import { useTransactionReceipt } from './useTransactionReceipt.js' + +test('default', async () => { + const [result] = renderComposable(() => + useTransactionReceipt({ + hash: '0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871', + }), + ) + + await waitFor(result.isSuccess) + + expect(deepUnref(result)).toMatchInlineSnapshot(` + { + "data": { + "blockHash": "0xb932f77cf770d1d1c8f861153eec1e990f5d56b6ffdb4ac06aef3cca51ef37d4", + "blockNumber": 16280769n, + "contractAddress": null, + "cumulativeGasUsed": 21000n, + "effectiveGasPrice": 33427926161n, + "from": "0x043022ef9fca1066024d19d681e2ccf44ff90de3", + "gasUsed": 21000n, + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "success", + "to": "0x318a5fb4f1604fc46375a1db9a9018b6e423b345", + "transactionHash": "0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871", + "transactionIndex": 0, + "type": "legacy", + }, + "dataUpdatedAt": 1675209600000, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "failureCount": 0, + "failureReason": null, + "fetchStatus": "idle", + "isError": false, + "isFetched": true, + "isFetchedAfterMount": true, + "isFetching": false, + "isInitialLoading": false, + "isLoading": false, + "isLoadingError": false, + "isPaused": false, + "isPending": false, + "isPlaceholderData": false, + "isRefetchError": false, + "isRefetching": false, + "isStale": true, + "isSuccess": true, + "queryKey": [ + "getTransactionReceipt", + { + "chainId": 1, + "hash": "0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871", + }, + ], + "refetch": [Function], + "status": "success", + "suspense": [Function], + } + `) +}) + +test('parameters: chainId', async () => { + const [result] = renderComposable(() => + useTransactionReceipt({ + chainId: chain.mainnet2.id, + hash: '0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871', + }), + ) + + await waitFor(result.isSuccess) + + expect(deepUnref(result)).toMatchInlineSnapshot(` + { + "data": { + "blockHash": "0xb932f77cf770d1d1c8f861153eec1e990f5d56b6ffdb4ac06aef3cca51ef37d4", + "blockNumber": 16280769n, + "contractAddress": null, + "cumulativeGasUsed": 21000n, + "effectiveGasPrice": 33427926161n, + "from": "0x043022ef9fca1066024d19d681e2ccf44ff90de3", + "gasUsed": 21000n, + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "success", + "to": "0x318a5fb4f1604fc46375a1db9a9018b6e423b345", + "transactionHash": "0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871", + "transactionIndex": 0, + "type": "legacy", + }, + "dataUpdatedAt": 1675209600000, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "failureCount": 0, + "failureReason": null, + "fetchStatus": "idle", + "isError": false, + "isFetched": true, + "isFetchedAfterMount": true, + "isFetching": false, + "isInitialLoading": false, + "isLoading": false, + "isLoadingError": false, + "isPaused": false, + "isPending": false, + "isPlaceholderData": false, + "isRefetchError": false, + "isRefetching": false, + "isStale": true, + "isSuccess": true, + "queryKey": [ + "getTransactionReceipt", + { + "chainId": 456, + "hash": "0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871", + }, + ], + "refetch": [Function], + "status": "success", + "suspense": [Function], + } + `) +}) + +test('behavior: hash: undefined -> defined', async () => { + const hash = ref() + + const [result] = renderComposable(() => + useTransactionReceipt({ + hash, + }), + ) + + await wait(100) + expect(result.fetchStatus.value).toBe('idle') + + hash.value = + '0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871' + + await waitFor(result.isSuccess) + + expect(deepUnref(result)).toMatchInlineSnapshot(` + { + "data": { + "blockHash": "0xb932f77cf770d1d1c8f861153eec1e990f5d56b6ffdb4ac06aef3cca51ef37d4", + "blockNumber": 16280769n, + "contractAddress": null, + "cumulativeGasUsed": 21000n, + "effectiveGasPrice": 33427926161n, + "from": "0x043022ef9fca1066024d19d681e2ccf44ff90de3", + "gasUsed": 21000n, + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": "success", + "to": "0x318a5fb4f1604fc46375a1db9a9018b6e423b345", + "transactionHash": "0xbf7d27700d053765c9638d3b9d39eb3c56bfc48377583e8be483d61f9f18a871", + "transactionIndex": 0, + "type": "legacy", + }, + "dataUpdatedAt": 1675209600000, + "error": null, + "errorUpdateCount": 0, + "errorUpdatedAt": 0, + "failureCount": 0, + "failureReason": null, + "fetchStatus": "idle", + "isError": false, + "isFetched": true, + "isFetchedAfterMount": true, + "isFetching": false, + "isInitialLoading": false, + "isLoading": false, + "isLoadingError": false, + "isPaused": false, + "isPending": false, + "isPlaceholderData": false, + "isRefetchError": false, + "isRefetching": false, + "isStale": true, + "isSuccess": true, + "queryKey": [ + "getTransactionReceipt", + { + "chainId": 1, + "hash": undefined, + }, + ], + "refetch": [Function], + "status": "success", + "suspense": [Function], + } + `) +}) + +test('behavior: disabled when properties missing', async () => { + const [result] = renderComposable(() => useTransactionReceipt()) + + await wait(100) + expect(result.fetchStatus.value).toBe('idle') +}) diff --git a/packages/vue/src/composables/useTransactionReceipt.ts b/packages/vue/src/composables/useTransactionReceipt.ts new file mode 100644 index 0000000000..13a5ccfdbb --- /dev/null +++ b/packages/vue/src/composables/useTransactionReceipt.ts @@ -0,0 +1,85 @@ +import { + type Config, + type GetTransactionReceiptErrorType, + type ResolvedRegister, +} from '@wagmi/core' +import { type Evaluate } from '@wagmi/core/internal' +import { + type GetTransactionReceiptData, + type GetTransactionReceiptOptions, + type GetTransactionReceiptQueryKey, + getTransactionReceiptQueryOptions, +} from '@wagmi/core/query' +import { type GetTransactionReceiptQueryFnData } from '@wagmi/core/query' + +import { computed } from 'vue' +import { + type ConfigParameter, + type QueryParameter, +} from '../types/properties.js' +import type { DeepMaybeRef } from '../types/ref.js' +import { deepUnref } from '../utils/cloneDeep.js' +import { type UseQueryReturnType, useQuery } from '../utils/query.js' +import { useChainId } from './useChainId.js' +import { useConfig } from './useConfig.js' + +export type UseTransactionReceiptParameters< + config extends Config = Config, + chainId extends config['chains'][number]['id'] = config['chains'][number]['id'], + selectData = GetTransactionReceiptData, +> = Evaluate< + DeepMaybeRef< + GetTransactionReceiptOptions & + ConfigParameter & + QueryParameter< + GetTransactionReceiptQueryFnData, + GetTransactionReceiptErrorType, + selectData, + GetTransactionReceiptQueryKey + > + > +> + +export type UseTransactionReceiptReturnType< + config extends Config = Config, + chainId extends config['chains'][number]['id'] = config['chains'][number]['id'], + selectData = GetTransactionReceiptData, +> = UseQueryReturnType + +/** https://wagmi.sh/vue/api/composables/useTransactionReceipt */ +export function useTransactionReceipt< + config extends Config = ResolvedRegister['config'], + chainId extends config['chains'][number]['id'] = config['chains'][number]['id'], + selectData = GetTransactionReceiptData, +>( + parameters_: UseTransactionReceiptParameters< + config, + chainId, + selectData + > = {}, +): UseTransactionReceiptReturnType { + const parameters = computed(() => deepUnref(parameters_)) + + const config = useConfig(parameters) + const configChainId = useChainId({ config }) + + const queryOptions = computed(() => { + const { chainId = configChainId.value, hash, query = {} } = parameters.value + const options = getTransactionReceiptQueryOptions(config, { + ...parameters.value, + chainId, + }) + const enabled = Boolean(hash && (query.enabled ?? true)) + return { + ...(query as any), + ...options, + enabled, + } + }) + + return useQuery(queryOptions) as UseTransactionReceiptReturnType< + config, + chainId, + selectData + > +} diff --git a/packages/vue/src/composables/useWaitForTransactionReceipt.test.ts b/packages/vue/src/composables/useWaitForTransactionReceipt.test.ts index 3fc015177c..3cfcbe0feb 100644 --- a/packages/vue/src/composables/useWaitForTransactionReceipt.test.ts +++ b/packages/vue/src/composables/useWaitForTransactionReceipt.test.ts @@ -10,7 +10,7 @@ test('default', async () => { }), ) - await waitFor(result.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(result.isSuccess) expect(result.data.value).toMatchInlineSnapshot(` { diff --git a/packages/vue/src/composables/useWriteContract.test.ts b/packages/vue/src/composables/useWriteContract.test.ts index fc576b1fbf..ba7c8cb4cb 100644 --- a/packages/vue/src/composables/useWriteContract.test.ts +++ b/packages/vue/src/composables/useWriteContract.test.ts @@ -17,7 +17,7 @@ test('default', async () => { address: address.wagmiMintExample, functionName: 'mint', }) - await waitFor(result.isSuccess, (isSuccess) => Boolean(isSuccess)) + await waitFor(result.isSuccess) expect(result.data.value).toBeDefined() diff --git a/packages/vue/src/exports/index.ts b/packages/vue/src/exports/index.ts index bc0315d2d5..7c8cdd41b1 100644 --- a/packages/vue/src/exports/index.ts +++ b/packages/vue/src/exports/index.ts @@ -170,6 +170,12 @@ export { useTransaction, } from '../composables/useTransaction.js' +export { + type UseTransactionReceiptParameters, + type UseTransactionReceiptReturnType, + useTransactionReceipt, +} from '../composables/useTransactionReceipt.js' + export { type UseWatchBlockNumberParameters, type UseWatchBlockNumberReturnType, diff --git a/site/.vitepress/sidebar.ts b/site/.vitepress/sidebar.ts index ef232c77e5..95c6491d7d 100644 --- a/site/.vitepress/sidebar.ts +++ b/site/.vitepress/sidebar.ts @@ -563,6 +563,10 @@ export function getSidebar() { text: 'useTransaction', link: '/vue/api/composables/useTransaction', }, + { + text: 'useTransactionReceipt', + link: '/vue/api/composables/useTransactionReceipt', + }, { text: 'useWaitForTransactionReceipt', link: '/vue/api/composables/useWaitForTransactionReceipt', diff --git a/site/vue/api/composables/useTransactionReceipt.md b/site/vue/api/composables/useTransactionReceipt.md new file mode 100644 index 0000000000..e610c23840 --- /dev/null +++ b/site/vue/api/composables/useTransactionReceipt.md @@ -0,0 +1,141 @@ +--- +title: useTransactionReceipt +description: Composable for return the Transaction Receipt given a Transaction hash. +--- + + + +# useTransactionReceipt + +Composable for return the [Transaction Receipt](https://viem.sh/docs/glossary/terms.html#transaction-receipt) given a [Transaction](https://viem.sh/docs/glossary/terms.html#transaction) hash. + +## Import + +```ts +import { useTransactionReceipt } from '@wagmi/vue' +``` + +## Usage + +::: code-group +```vue [index.vue] + +``` +<<< @/snippets/vue/config.ts[config.ts] +::: + +## Parameters + +```ts +import { type UseTransactionReceiptParameters } from '@wagmi/vue' +``` + +### hash + +`` `0x${string}` | undefined `` + +A transaction hash. + +::: code-group +```vue [index.vue] + +``` +<<< @/snippets/vue/config.ts[config.ts] +::: + +### chainId + +`config['chains'][number]['id'] | undefined` + +The ID of chain to return the transaction receipt from. + +::: code-group +```vue [index.vue] + +``` +<<< @/snippets/vue/config.ts[config.ts] +::: + +### config + +`Config | undefined` + +[`Config`](/vue/api/createConfig#config) to use instead of retrieving from the [`WagmiPlugin`](/vue/api/WagmiPlugin). + +::: code-group +```vue [index.vue] + +``` +<<< @/snippets/vue/config.ts[config.ts] +::: + +### scopeKey + +`string | undefined` + +Scopes the cache to a given context. Composables that have identical context will share the same cache. + +::: code-group +```vue [index.vue] + +``` +<<< @/snippets/vue/config.ts[config.ts] +::: + + + +## Return Type + +```ts +import { type UseTransactionReceiptReturnType } from '@wagmi/vue' +``` + + + + + +## Action + +- [`getTransactionReceipt`](/core/api/actions/getTransactionReceipt)