Skip to content

Commit

Permalink
feat(zksync,actions): add getL1TokenAddress public action
Browse files Browse the repository at this point in the history
  • Loading branch information
danijelTxFusion committed Dec 12, 2024
1 parent 04d3274 commit 61c12aa
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/green-squids-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"viem": minor
---

Added `getL1TokenAddress` public action to the `ZKsync` extension
58 changes: 58 additions & 0 deletions site/pages/zksync/actions/getL1TokenAddress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
description: Returns the L1 token address equivalent for a L2 token address as they are not equal.
---

# getL1TokenAddress

Returns the L1 token address equivalent for a L2 token address as they are not equal.

:::info

Only works for tokens bridged on default ZKsync Era bridges.

:::

## Usage

:::code-group

```ts [example.ts]
import { account, publicClient } from './config'

const address = await client.getL1TokenAddress({
token: '0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b'
})
```

```ts [config.ts]
import { createPublicClient, http } from 'viem'
import { zksync } from 'viem/chains'
import { publicActionsL2 } from 'viem/zksync'

export const client = createPublicClient({
chain: zksync,
transport: http(),
}).extend(publicActionsL2())
```

:::

## Returns

`Address`

Returns the L1 token address equivalent for a L2 token address.

## Parameters

### token

- **Type:** `Address`

The address of the token on L2.

```ts
const address = await client.getL1TokenAddress({
token: '0x3e7676937A7E96CFB7616f255b9AD9FF47363D4b'
})
```
4 changes: 4 additions & 0 deletions site/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,10 @@ export const sidebar = {
text: 'getL1ChainId',
link: '/zksync/actions/getL1ChainId',
},
{
text: 'getL1TokenAddress',
link: '/zksync/actions/getL1TokenAddress',
},
{
text: 'getL2TokenAddress',
link: '/zksync/actions/getL2TokenAddress',
Expand Down
44 changes: 44 additions & 0 deletions src/zksync/actions/getL1TokenAddress.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { expect, test } from 'vitest'
import { daiL1 } from '../../../test/src/zksync.js'
import { http, createClient } from '../../index.js'
import {
zksyncLocalCustomHyperchain,
zksyncLocalHyperchain,
} from '../chains.js'
import { legacyEthAddress } from '../constants/address.js'
import { getL1TokenAddress } from './getL1TokenAddress.js'
import { getL2TokenAddress } from './getL2TokenAddress.js'

const client = createClient({
chain: zksyncLocalHyperchain,
transport: http(),
})

const customChainClient = createClient({
chain: zksyncLocalCustomHyperchain,
transport: http(),
})

test('ETH: provided token address is L2 ETH address', async () => {
expect(await getL1TokenAddress(client, { token: legacyEthAddress })).toBe(
legacyEthAddress,
)
})

test('ETH: provided token address is L1 DAI address', async () => {
const daiL2 = await getL2TokenAddress(client, { token: daiL1 })
expect(await getL1TokenAddress(client, { token: daiL2 })).toBe(daiL1)
})

test('Custom: provided token address is L2 ETH address', async () => {
expect(await getL1TokenAddress(client, { token: legacyEthAddress })).toBe(
legacyEthAddress,
)
})

test('Custom: provided token address is L1 DAI address', async () => {
const daiL2 = await getL2TokenAddress(customChainClient, { token: daiL1 })
expect(await getL1TokenAddress(customChainClient, { token: daiL2 })).toBe(
daiL1,
)
})
37 changes: 37 additions & 0 deletions src/zksync/actions/getL1TokenAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { Address } from '../../accounts/index.js'
import { readContract } from '../../actions/public/readContract.js'
import type { Client } from '../../clients/createClient.js'
import type { Transport } from '../../clients/transports/createTransport.js'
import type { Account } from '../../types/account.js'
import type { Chain } from '../../types/chain.js'
import { isAddressEqual } from '../../utils/index.js'
import { l2SharedBridgeAbi } from '../constants/abis.js'
import { legacyEthAddress } from '../constants/address.js'
import { getDefaultBridgeAddresses } from './getDefaultBridgeAddresses.js'

export type GetL1TokenAddressParameters = {
/** The address of the token on L2. */
token: Address
}

export type GetL1TokenAddressReturnType = Address

export async function getL1TokenAddress<
chain extends Chain | undefined,
account extends Account | undefined,
>(
client: Client<Transport, chain, account>,
parameters: GetL1TokenAddressParameters,
): Promise<Address> {
const { token } = parameters
if (isAddressEqual(token, legacyEthAddress)) return legacyEthAddress

const bridgeAddress = (await getDefaultBridgeAddresses(client)).sharedL2

return await readContract(client, {
address: bridgeAddress,
abi: l2SharedBridgeAbi,
functionName: 'l1TokenAddress',
args: [token],
})
}
9 changes: 9 additions & 0 deletions src/zksync/decorators/publicL2.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
mockedL1BatchNumber,
} from '~test/src/zksync.js'
import { http } from '~viem/clients/transports/http.js'
import { legacyEthAddress } from '~viem/zksync/constants/address.js'
import { createPublicClient } from '../../clients/createPublicClient.js'
import { custom } from '../../clients/transports/custom.js'
import { estimateFee } from '../actions/estimateFee.js'
Expand Down Expand Up @@ -223,3 +224,11 @@ test('getL2TokenAddress', async () => {
}),
).toBeDefined()
})

test('getL1TokenAddress', async () => {
expect(
await zksyncClient.getL1TokenAddress({
token: legacyEthAddress,
}),
).toBeDefined()
})
32 changes: 32 additions & 0 deletions src/zksync/decorators/publicL2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ import {
type GetL1ChainIdReturnType,
getL1ChainId,
} from '../actions/getL1ChainId.js'
import {
type GetL1TokenAddressParameters,
type GetL1TokenAddressReturnType,
getL1TokenAddress,
} from '../actions/getL1TokenAddress.js'
import {
type GetL2TokenAddressParameters,
type GetL2TokenAddressReturnType,
Expand Down Expand Up @@ -442,6 +447,32 @@ export type PublicActionsL2<
getL2TokenAddress: (
args: GetL2TokenAddressParameters,
) => Promise<GetL2TokenAddressReturnType>

/**
* Returns the L1 token address equivalent for a L2 token address as they are not equal.
* ETH address is set to zero address.
*
* @remarks Only works for tokens bridged on default ZKsync Era bridges.
*
* @returns the L1 token address equivalent for a L2 token address.
* @param args - {@link GetL1TokenAddressParameters}
*
*
* @example
* import { createPublicClient, http } from 'viem'
* import { zksyncLocalNode } from 'viem/chains'
* import { publicActionsL2 } from 'viem/zksync'
*
* const client = createPublicClient({
* chain: zksyncLocalNode,
* transport: http(),
* }).extend(publicActionsL2())
*
* const address = await client.getL1TokenAddress({token: '0x...'});
*/
getL1TokenAddress: (
args: GetL1TokenAddressParameters,
) => Promise<GetL1TokenAddressReturnType>
}

export function publicActionsL2() {
Expand Down Expand Up @@ -470,6 +501,7 @@ export function publicActionsL2() {
getBridgehubContractAddress: () => getBridgehubContractAddress(client),
getBaseTokenL1Address: () => getBaseTokenL1Address(client),
getL2TokenAddress: (args) => getL2TokenAddress(client, args),
getL1TokenAddress: (args) => getL1TokenAddress(client, args),
}
}
}
5 changes: 5 additions & 0 deletions src/zksync/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ export {
type GetL2TokenAddressParameters,
getL2TokenAddress,
} from './actions/getL2TokenAddress.js'
export {
type GetL1TokenAddressReturnType,
type GetL1TokenAddressParameters,
getL1TokenAddress,
} from './actions/getL1TokenAddress.js'

export {
/** @deprecated Use `zksync` instead */
Expand Down

0 comments on commit 61c12aa

Please sign in to comment.