Skip to content

ZKsync: add support for v26, remove support for v25 #3555

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/breezy-eyes-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": patch
---

Added support for ZKsync v26, removed support for v25.
157 changes: 157 additions & 0 deletions site/pages/zksync/actions/claimFailedDeposit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
---
description: Withdraws funds from the initiated deposit, which failed when finalizing on L2.
---

# claimFailedDeposit

Withdraws funds from the initiated deposit, which failed when finalizing on L2.
If the deposit L2 transaction has failed, it sends an L1 transaction calling `claimFailedDeposit` method of the
L1 bridge, which results in returning L1 tokens back to the depositor.

## Usage

:::code-group

```ts [example.ts]
import { account, walletClient, zksyncClient } from './config'
import { legacyEthAddress } from 'viem/zksync'

const hash = await walletClient.claimFailedDeposit({
account,
client: zksyncClient,
depositHash: '<L2_HASH_OF_FAILED_DEPOSIT>'
})
```

```ts [config.ts]
import { createWalletClient, createPublicClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { zksync, mainnet } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'

export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())

export const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum)
}).extend(walletActionsL1())

// JSON-RPC Account
export const [account] = await walletClient.getAddresses()
// Local Account
export const account = privateKeyToAccount(...)
```

:::

### Account Hoisting

If you do not wish to pass an `account` to every `claimFailedDeposit`, you can also hoist the Account on the Wallet Client (see `config.ts`).

[Learn more](/docs/clients/wallet#account).

:::code-group

```ts [example.ts]
import { walletClient, zksyncClient } from './config'
import { legacyEthAddress } from 'viem/zksync'

const hash = await walletClient.claimFailedDeposit({
client: zksyncClient,
depositHash: '<L2_HASH_OF_FAILED_DEPOSIT>'
})
```

```ts [config.ts (JSON-RPC Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'

export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())

// Retrieve Account from an EIP-1193 Provider. // [!code focus]
const [account] = await window.ethereum.request({ // [!code focus]
method: 'eth_requestAccounts' // [!code focus]
}) // [!code focus]

export const walletClient = createWalletClient({
account,
transport: custom(window.ethereum) // [!code focus]
}).extend(walletActionsL1())
```

```ts [config.ts (Local Account)]
import { createWalletClient, custom } from 'viem'
import { zksync } from 'viem/chains'
import { privateKeyToAccount } from 'viem/accounts'
import { publicActionsL2, walletActionsL1 } from 'viem/zksync'

export const zksyncClient = createPublicClient({
chain: zksync,
transport: custom(window.ethereum)
}).extend(publicActionsL2())

export const walletClient = createWalletClient({
account: privateKeyToAccount('0x...'), // [!code focus]
transport: custom(window.ethereum)
}).extend(walletActionsL1())
```

:::

## Returns

[`Hash`](/docs/glossary/types#hash)

The [Transaction](/docs/glossary/terms#transaction) hash.

## Parameters

### client

- **Type:** `Client`

The L2 client for fetching data from L2 chain.

```ts
const hash = await walletClient.claimFailedDeposit({
client: zksyncClient, // [!code focus]
depositHash: '<L2_HASH_OF_FAILED_DEPOSIT>'
})
```

### depositHash

- **Type:** `Hash`

The L2 transaction hash of the failed deposit.

```ts
const hash = await walletClient.claimFailedDeposit({
client: zksyncClient,
depositHash: '<L2_HASH_OF_FAILED_DEPOSIT>', // [!code focus]
})
```

### chain (optional)

- **Type:** [`Chain`](/docs/glossary/types#chain)
- **Default:** `walletClient.chain`

The target chain. If there is a mismatch between the wallet's current chain & the target chain, an error will be thrown.

```ts
import { zksync } from 'viem/chains' // [!code focus]

const hash = await walletClient.claimFailedDeposit({
chain: zksync, // [!code focus]
client: zksyncClient,
depositHash: '<L2_HASH_OF_FAILED_DEPOSIT>'
})
```
4 changes: 4 additions & 0 deletions site/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1840,6 +1840,10 @@ export const sidebar = {
text: 'deposit',
link: '/zksync/actions/deposit',
},
{
text: 'claimFailedDeposit',
link: '/zksync/actions/claimFailedDeposit',
},
],
},
{
Expand Down
93 changes: 93 additions & 0 deletions src/zksync/actions/claimFailedDeposit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { expect, test } from 'vitest'
import { anvilMainnet, anvilZksync } from '~test/src/anvil.js'
import { accounts } from '~test/src/constants.js'
import {
mockFailedDepositReceipt,
mockFailedDepositTransaction,
mockLogProof,
mockRequestReturnData,
} from '~test/src/zksync.js'
import { privateKeyToAccount } from '~viem/accounts/privateKeyToAccount.js'
import { type EIP1193RequestFn, publicActions } from '~viem/index.js'
import { claimFailedDeposit } from '~viem/zksync/actions/claimFailedDeposit.js'
import { publicActionsL2 } from '~viem/zksync/index.js'

const request = (async ({ method, params }) => {
if (method === 'eth_sendRawTransaction')
return '0x9afe47f3d95eccfc9210851ba5f877f76d372514a26b48bad848a07f77c33b87'
if (method === 'eth_sendTransaction')
return '0x9afe47f3d95eccfc9210851ba5f877f76d372514a26b48bad848a07f77c33b87'
if (method === 'eth_estimateGas') return 158774n
if (method === 'eth_gasPrice') return 150_000_000n
if (method === 'eth_maxPriorityFeePerGas') return 100_000_000n
if (method === 'eth_call')
return '0x00000000000000000000000070a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55'
if (method === 'eth_getTransactionCount') return 1n
if (method === 'eth_getBlockByNumber') return anvilMainnet.forkBlockNumber
if (method === 'eth_chainId') return anvilMainnet.chain.id
return anvilMainnet.getClient().request({ method, params } as any)
}) as EIP1193RequestFn

const baseClient = anvilMainnet.getClient({ batch: { multicall: false } })
baseClient.request = request
const client = baseClient.extend(publicActions)

const baseClientWithAccount = anvilMainnet.getClient({
batch: { multicall: false },
account: true,
})
baseClientWithAccount.request = request
const clientWithAccount = baseClientWithAccount.extend(publicActions)

const baseClientL2 = anvilZksync.getClient()
baseClientL2.request = (async ({ method, params }) => {
if (method === 'eth_getTransactionReceipt') return mockFailedDepositReceipt
if (method === 'eth_getTransactionByHash') return mockFailedDepositTransaction
if (method === 'zks_getL2ToL1LogProof') return mockLogProof
if (method === 'eth_call')
return '0x00000000000000000000000070a0F165d6f8054d0d0CF8dFd4DD2005f0AF6B55'
if (method === 'eth_estimateGas') return 158774n
return (
(await mockRequestReturnData(method)) ??
(await anvilZksync.getClient().request({ method, params } as any))
)
}) as EIP1193RequestFn
const clientL2 = baseClientL2.extend(publicActionsL2())

test.skip('default', async () => {
const account = privateKeyToAccount(accounts[0].privateKey)
expect(
claimFailedDeposit(client, {
client: clientL2,
account,
depositHash:
'0x5b08ec4c7ebb02c07a3f08bc5677aec87c47200f685f6389969a3c084bee13dc',
}),
).toBeDefined()
})

test('default: account hoisting', async () => {
expect(
claimFailedDeposit(clientWithAccount, {
client: clientL2,
depositHash:
'0x5b08ec4c7ebb02c07a3f08bc5677aec87c47200f685f6389969a3c084bee13dc',
}),
).toBeDefined()
})

test('errors: no account provided', async () => {
await expect(() =>
claimFailedDeposit(client, {
client: clientL2,
depositHash:
'0x5b08ec4c7ebb02c07a3f08bc5677aec87c47200f685f6389969a3c084bee13dc',
}),
).rejects.toThrowErrorMatchingInlineSnapshot(`
[AccountNotFoundError: Could not find an Account to execute with this Action.
Please provide an Account with the \`account\` argument on the Action, or by supplying an \`account\` to the Client.

Docs: https://viem.sh/docs/actions/wallet/sendTransaction
Version: [email protected]]
`)
})
Loading
Loading