diff --git a/.changeset/tall-pets-impress.md b/.changeset/tall-pets-impress.md new file mode 100644 index 0000000000..4e9b9ef99e --- /dev/null +++ b/.changeset/tall-pets-impress.md @@ -0,0 +1,5 @@ +--- +"viem": patch +--- + +Fixed account hoisting for `signEip712Transaction` and `sendEip712Transaction` in ZKsync extension. diff --git a/src/zksync/actions/sendEip712Transaction.ts b/src/zksync/actions/sendEip712Transaction.ts index 1804c69b2c..2ff0b06201 100644 --- a/src/zksync/actions/sendEip712Transaction.ts +++ b/src/zksync/actions/sendEip712Transaction.ts @@ -92,13 +92,15 @@ export async function sendEip712Transaction< request >, ): Promise { - const { chain = client.chain } = parameters + const { account: account_ = client.account, chain = client.chain } = + parameters - if (!parameters.account) + const account = account_ ? parseAccount(account_) : client.account + + if (!account) throw new AccountNotFoundError({ docsPath: '/docs/actions/wallet/sendTransaction', }) - const account = parseAccount(parameters.account) try { assertEip712Request(parameters) diff --git a/src/zksync/actions/signEip712Transaction.test.ts b/src/zksync/actions/signEip712Transaction.test.ts index 045c8fd74a..89ed44487d 100644 --- a/src/zksync/actions/signEip712Transaction.test.ts +++ b/src/zksync/actions/signEip712Transaction.test.ts @@ -2,7 +2,7 @@ import { expect, test } from 'vitest' import { accounts } from '~test/src/constants.js' -import { anvilZksync } from '../../../test/src/anvil.js' +import { anvilZksync } from '~test/src/anvil.js' import { privateKeyToAccount } from '../../accounts/privateKeyToAccount.js' import type { ZksyncTransactionRequestEIP712 } from '../../zksync/index.js' import { signTransaction } from './signTransaction.js' diff --git a/src/zksync/actions/signEip712Transaction.ts b/src/zksync/actions/signEip712Transaction.ts index ffb8eb3ed0..4257d98a7b 100644 --- a/src/zksync/actions/signEip712Transaction.ts +++ b/src/zksync/actions/signEip712Transaction.ts @@ -53,6 +53,8 @@ export type SignEip712TransactionErrorType = SignTransactionErrorType /** * Signs an EIP712 transaction. * + * + * @param client - Client to use * @param args - {@link SignTransactionParameters} * @returns The signed serialized transaction. {@link SignTransactionReturnType} * @@ -102,11 +104,12 @@ export async function signEip712Transaction< ...transaction } = args - if (!account_) + const account = account_ ? parseAccount(account_) : client.account + + if (!account) throw new AccountNotFoundError({ docsPath: '/docs/actions/wallet/signTransaction', }) - const account = parseAccount(account_) assertEip712Request({ account, diff --git a/src/zksync/decorators/eip712.test.ts b/src/zksync/decorators/eip712.test.ts index 7a34b0916d..40754561d9 100644 --- a/src/zksync/decorators/eip712.test.ts +++ b/src/zksync/decorators/eip712.test.ts @@ -1,8 +1,8 @@ import { expect, test } from 'vitest' import { greeterContract } from '~test/src/abis.js' +import { anvilZksync } from '~test/src/anvil.js' import { accounts } from '~test/src/constants.js' -import { anvilZksync } from '../../../test/src/anvil.js' import { privateKeyToAccount } from '../../accounts/privateKeyToAccount.js' import { simulateContract } from '../../actions/index.js' import type { EIP1193RequestFn } from '../../types/eip1193.js' @@ -11,6 +11,9 @@ import { eip712WalletActions } from './eip712.js' const client = anvilZksync.getClient() const zksyncClient = client.extend(eip712WalletActions()) +const clientWithAccount = anvilZksync.getClient({ account: true }) +const zksyncClientWithAccount = clientWithAccount.extend(eip712WalletActions()) + test('default', async () => { expect(eip712WalletActions()(client)).toMatchInlineSnapshot(` { @@ -47,6 +50,32 @@ test('sendTransaction', async () => { expect(result).toBeDefined() }) +test('sendTransaction with account hoisting', async () => { + zksyncClientWithAccount.request = (async ({ method, params }) => { + if (method === 'eth_sendRawTransaction') + return '0x9afe47f3d95eccfc9210851ba5f877f76d372514a26b48bad848a07f77c33b87' + if (method === 'eth_signTypedData_v4') + return '0x71f8da808502540be4008502540be40083026c369470997970c51812dc3a010c7d01b50e0d17dc79c88502540be4000082014480808201448082c350c0b841cee039b6d00ff61277ac416a0c98d23d9bfc64e024cd3d3f946ab33cdfe4576b5e4d3bed2c0a2383a1a13f0777b46ca2c19edefb67d8d8584af7d963f5284ca81bf85b94fd9ae5ebb0f6656f4b77a0e99dcbc5138d54b0bab8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000' + return anvilZksync.getClient().request({ method, params } as any) + }) as EIP1193RequestFn + const client = zksyncClientWithAccount.extend(eip712WalletActions()) + + const result = await client.sendTransaction({ + to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', + maxFeePerGas: 10000000000n, + maxPriorityFeePerGas: 10000000000n, + gas: 158774n, + value: 10000000000n, + data: '0x0', + paymaster: '0xFD9aE5ebB0F6656f4b77a0E99dCbc5138d54b0BA', + paymasterInput: + '0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', + type: 'eip712', + gasPerPubdata: 50000n, + }) + expect(result).toBeDefined() +}) + test('signTransaction', async () => { const signature = await zksyncClient.signTransaction({ account: privateKeyToAccount(accounts[0].privateKey), @@ -65,6 +94,32 @@ test('signTransaction', async () => { expect(signature).toBeDefined() }) +test('signTransaction with account hoisting', async () => { + zksyncClientWithAccount.request = (async ({ method, params }) => { + if (method === 'eth_signTypedData_v4') + return '0x71f8da808502540be4008502540be40083026c369470997970c51812dc3a010c7d01b50e0d17dc79c88502540be4000082014480808201448082c350c0b841cee039b6d00ff61277ac416a0c98d23d9bfc64e024cd3d3f946ab33cdfe4576b5e4d3bed2c0a2383a1a13f0777b46ca2c19edefb67d8d8584af7d963f5284ca81bf85b94fd9ae5ebb0f6656f4b77a0e99dcbc5138d54b0bab8448c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000' + return anvilZksync + .getClient({ account: true }) + .request({ method, params } as any) + }) as EIP1193RequestFn + const client = zksyncClientWithAccount.extend(eip712WalletActions()) + + const signature = await client.signTransaction({ + to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8', + maxFeePerGas: 10000000000n, + maxPriorityFeePerGas: 10000000000n, + gas: 158774n, + value: 10000000000n, + data: '0x0', + paymaster: '0xFD9aE5ebB0F6656f4b77a0E99dCbc5138d54b0BA', + paymasterInput: + '0x8c5a344500000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000', + type: 'eip712', + gasPerPubdata: 50000n, + }) + expect(signature).toBeDefined() +}) + test('writeContract', async () => { zksyncClient.request = (async ({ method, params }) => { if (method === 'eth_sendRawTransaction') diff --git a/test/src/zksync.ts b/test/src/zksync.ts index 54f5220a8d..3c29b952f5 100644 --- a/test/src/zksync.ts +++ b/test/src/zksync.ts @@ -1,7 +1,7 @@ import { zksyncLocalNode } from '~viem/chains/index.js' import { createClient } from '~viem/clients/createClient.js' import { http } from '~viem/index.js' -import { accounts } from './constants.js' +import { accounts as acc } from './constants.js' export const zksyncClientLocalNode = createClient({ chain: zksyncLocalNode, @@ -9,7 +9,7 @@ export const zksyncClientLocalNode = createClient({ }) export const zksyncClientLocalNodeWithAccount = createClient({ - account: accounts[0].address, + account: acc[0].address, chain: zksyncLocalNode, transport: http(), }) @@ -209,3 +209,16 @@ export function mockClientPublicActionsL2(client: any) { return mockRequestReturnData(method) } } + +export const accounts = [ + { + address: '0x36615Cf349d7F6344891B1e7CA7C72883F5dc049', + privateKey: + '0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110', + }, + { + address: '0xa61464658AfeAf65CccaaFD3a512b69A83B77618', + privateKey: + '0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3', + }, +] as const