Skip to content

Commit 7df5678

Browse files
authored
ALL-6929 Add zkSync rpc (#1122)
1 parent 9c5cced commit 7df5678

17 files changed

+435
-107
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [4.2.37] - 2024.7.23
2+
3+
### Added
4+
5+
- Support for zkSync mainnet & testnet
6+
17
## [4.2.36] - 2024.7.18
28

39
### Added

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tatumio/tatum",
3-
"version": "4.2.36",
3+
"version": "4.2.37",
44
"description": "Tatum JS SDK",
55
"author": "Tatum",
66
"repository": "https://github.com/tatumio/tatum-js",

src/dto/Currency.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ export enum Currency {
5252
ATOM = 'ATOM',
5353
IOTA = 'IOTA',
5454
CSPR = 'CSPR',
55-
TON = 'TON'
55+
TON = 'TON',
56+
ZKS = 'ZKS',
5657
}
5758

5859
export function networkToCurrency(network: Network): Currency {

src/dto/Network.ts

+22-2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export enum Network {
5757
BITCOIN_ELECTRS = 'bitcoin-mainnet-electrs',
5858
CASPER = 'casper-mainnet',
5959
TON = 'ton-mainnet',
60+
ZK_SYNC = 'zks-mainnet',
6061

6162

6263
// Testnets
@@ -111,7 +112,8 @@ export enum Network {
111112
IOTA_TESTNET = 'iota-testnet',
112113
BITCOIN_ELECTRS_TESTNET = 'bitcoin-testnet-electrs',
113114
ROSTRUM_TESTNET = 'bch-testnet-rostrum',
114-
TON_TESTNET = 'ton-testnet'
115+
TON_TESTNET = 'ton-testnet',
116+
ZK_SYNC_TESTNET = 'zks-testnet',
115117
}
116118

117119
export const EVM_BASED_NETWORKS = [
@@ -163,6 +165,8 @@ export const EVM_BASED_NETWORKS = [
163165
Network.HORIZEN_EON,
164166
Network.HORIZEN_EON_GOBI,
165167
Network.CHILIZ,
168+
Network.ZK_SYNC,
169+
Network.ZK_SYNC_TESTNET,
166170
]
167171

168172
export const UTXO_BASED_NETWORKS = [
@@ -216,6 +220,8 @@ export const UTXO_LOAD_BALANCER_NETWORKS = [
216220

217221
export const DOGECOIN_LOAD_BALANCED_NETWORKS = [Network.DOGECOIN, Network.DOGECOIN_TESTNET]
218222

223+
export const ZK_SYNC_LOAD_BALANCER_NETWORKS = [Network.ZK_SYNC, Network.ZK_SYNC_TESTNET]
224+
219225
export const EVM_LOAD_BALANCER_NETWORKS = [
220226
Network.FLARE,
221227
Network.FLARE_COSTON,
@@ -243,8 +249,10 @@ export const EVM_LOAD_BALANCER_NETWORKS = [
243249
Network.FANTOM,
244250
Network.CRONOS,
245251
Network.BASE,
252+
...ZK_SYNC_LOAD_BALANCER_NETWORKS,
246253
]
247254

255+
248256
export const TRON_LOAD_BALANCER_NETWORKS = [Network.TRON]
249257
export const EOS_LOAD_BALANCER_NETWORKS = [Network.EOS]
250258
export const XRP_LOAD_BALANCER_NETWORKS = [Network.XRP, Network.XRP_TESTNET]
@@ -390,6 +398,8 @@ export const isIotaNetwork = (network: Network) => IOTA_NETWORKS.includes(networ
390398

391399
export const isElectrsNetwork = (network: Network) => BITCOIN_ELECTRS_NETWORKS.includes(network)
392400

401+
export const isZkSyncNetwork = (network: Network) => ZK_SYNC_LOAD_BALANCER_NETWORKS.includes(network)
402+
393403
export const isCasperNetwork = (network: Network) => CASPER_NETWORKS.includes(network)
394404

395405
export const isTonNetwork = (network: Network) => TON_NETWORKS.includes(network)
@@ -974,5 +984,15 @@ export const NETWORK_METADATA: Record<Network, NetworkMetadata> = {
974984
[Network.TON_TESTNET]: {
975985
currency: Currency.TON,
976986
testnet: true
977-
}
987+
},
988+
[Network.ZK_SYNC]: {
989+
currency: Currency.ZKS,
990+
testnet: false,
991+
chainId: 324
992+
},
993+
[Network.ZK_SYNC_TESTNET]: {
994+
currency: Currency.ZKS,
995+
testnet: true,
996+
chainId: 300
997+
},
978998
}

src/dto/rpc/ZkSyncRpcSuite.ts

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* eslint-disable @typescript-eslint/no-explicit-any */
2+
3+
import { EvmBasedRpcInterface, TxPayload } from './EvmBasedRpcInterface'
4+
import { JsonRpcResponse } from '../JsonRpcResponse.dto'
5+
import { BigNumber } from 'bignumber.js'
6+
import { AbstractRpcInterface } from './AbstractJsonRpcInterface'
7+
8+
export interface BridgeContracts {
9+
l1Erc20DefaultBridge: string
10+
l2Erc20DefaultBridge: string
11+
l1WethBridge: string
12+
l2WethBridge: string
13+
}
14+
15+
export interface TokenDetails {
16+
l1Address: string
17+
l2Address: string
18+
name: string
19+
symbol: string
20+
decimals: number
21+
}
22+
23+
export interface TokenMapping {
24+
[key: string]: string
25+
}
26+
27+
export interface ZksGetL2ToL1MsgProofParams {
28+
block: number
29+
sender: string
30+
msg: string
31+
l2_log_position?: string
32+
}
33+
34+
export interface ZksGetL2ToL1ProofResponse {
35+
id: string
36+
proof: string[]
37+
root: string
38+
}
39+
40+
export interface GetProofParams {
41+
data: string
42+
arrayOfData: string[]
43+
timePoint: number
44+
}
45+
46+
export interface StorageProof {
47+
key: string;
48+
value: string;
49+
index: number;
50+
proof: string[];
51+
}
52+
53+
export interface GetProofResponse {
54+
address: string;
55+
storageProof: StorageProof[];
56+
}
57+
58+
export interface ZkSyncRpcSuite extends ZkSyncRpcInterface, AbstractRpcInterface {}
59+
60+
export interface ZkSyncRpcInterface extends EvmBasedRpcInterface {
61+
zksEstimateFee(payload: TxPayload): Promise<JsonRpcResponse<any>>
62+
zksEstimateGasL1ToL2(payload: TxPayload): Promise<JsonRpcResponse<BigNumber>>
63+
zksGetBridgeHubContract(): Promise<JsonRpcResponse<string>>
64+
zksGetMinContract(): Promise<JsonRpcResponse<string>>
65+
zksGetBridgeContracts(): Promise<JsonRpcResponse<BridgeContracts>>
66+
zksL1ChainId(): Promise<JsonRpcResponse<BigNumber>>
67+
zksGetBaseTokenL1Address(): Promise<JsonRpcResponse<string>>
68+
zksGetConfirmedTokens(tokenIdToStart: number, maxTokens: number): Promise<JsonRpcResponse<TokenDetails[]>>
69+
zksGetAllAccountBalances(address: string): Promise<JsonRpcResponse<TokenMapping>>
70+
zksGetL2ToL1MsgProof(payload: ZksGetL2ToL1MsgProofParams): Promise<JsonRpcResponse<ZksGetL2ToL1ProofResponse>>
71+
zksGetL2ToL1LogProof(txHash: string, logIndex?: number): Promise<JsonRpcResponse<ZksGetL2ToL1ProofResponse>>
72+
zksL1BatchNumber(): Promise<JsonRpcResponse<BigNumber>>
73+
zksGetBlockDetails(blockNumber: number): Promise<JsonRpcResponse<any>>
74+
zksGetTransactionDetails(txHash: string): Promise<JsonRpcResponse<any>>
75+
zksGetRawBlockTransactions(blockNumber: number): Promise<JsonRpcResponse<any>>
76+
zksGetL1BatchDetails(batchNumber: number): Promise<JsonRpcResponse<any>>
77+
zksGetBytecodeByHash(txHash: string): Promise<JsonRpcResponse<number[]>>
78+
zksGetL1BatchBlockRange(batchNumber: number): Promise<JsonRpcResponse<string[]>>
79+
zksGetL1GasPrice(): Promise<JsonRpcResponse<BigNumber>>
80+
zksGetFeeParams(): Promise<JsonRpcResponse<any>>
81+
zksGetProtocolVersion(versionId?: number): Promise<JsonRpcResponse<any>>
82+
zksGetProof(payload: GetProofParams): Promise<JsonRpcResponse<GetProofResponse>>
83+
zksSendRawTransactionWithDetailedOutput(data: string): Promise<JsonRpcResponse<any>>
84+
}

src/e2e/e2e.util.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import {
88
FullSdk,
99
Network,
1010
NotificationSubscription,
11+
RpcNodeType,
12+
TatumConfig,
1113
} from '../service'
1214
import { ResponseDto } from '../util'
1315
import { NetworkUtils } from '../util/network.utils'
1416

1517
export const e2eUtil = {
16-
initConfig: (network: Network, apiKey?: string) => {
17-
return {
18+
initConfig: (network: Network, apiKey?: string, url?: string) => {
19+
const config: TatumConfig = {
1820
network,
1921
verbose: e2eUtil.isVerbose,
2022
retryCount: 5,
@@ -23,6 +25,13 @@ export const e2eUtil = {
2325
v4: apiKey ?? NetworkUtils.getV4ApiKeyForNetwork(network),
2426
},
2527
}
28+
29+
if (url) {
30+
config.rpc = {
31+
nodes: [{ url: url, type: RpcNodeType.NORMAL }]
32+
}
33+
}
34+
return config
2635
},
2736
subscriptions: {
2837
getAddress: (network: Network): string => {

src/e2e/rpc/evm/evm.e2e.utils.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,24 @@ interface EvmE2eI {
1111
estimateGas?: any
1212
}
1313
skipEstimateGas?: boolean
14+
url?: string
1415
}
1516

1617
export const EvmE2eUtils = {
17-
initTatum: async <T extends BaseEvm>(network: Network, apiKey?: string) =>
18-
TatumSDK.init<T>(e2eUtil.initConfig(network, apiKey)),
18+
initTatum: async <T extends BaseEvm>(network: Network, apiKey?: string, url?: string) =>
19+
TatumSDK.init<T>(e2eUtil.initConfig(network, apiKey, url)),
1920
e2e: (evmE2eI: EvmE2eI) => {
20-
const { network, data, skipEstimateGas, apiKey } = evmE2eI
21+
const { network, data, skipEstimateGas, apiKey, url } = evmE2eI
2122
it('eth_blockNumber', async () => {
22-
const tatum = await EvmE2eUtils.initTatum(network, apiKey)
23+
const tatum = await EvmE2eUtils.initTatum(network, apiKey, url)
2324
const { result } = await tatum.rpc.blockNumber()
2425

2526
await tatum.destroy()
2627
expect(result?.toNumber()).toBeGreaterThan(0)
2728
})
2829

2930
it('eth_chainId', async () => {
30-
const tatum = await EvmE2eUtils.initTatum(network, apiKey)
31+
const tatum = await EvmE2eUtils.initTatum(network, apiKey, url)
3132
const { result } = await tatum.rpc.chainId()
3233

3334
tatum.rpc.destroy()
@@ -36,7 +37,7 @@ export const EvmE2eUtils = {
3637

3738
if (!skipEstimateGas) {
3839
it('eth_estimateGas', async () => {
39-
const tatum = await EvmE2eUtils.initTatum(network, apiKey)
40+
const tatum = await EvmE2eUtils.initTatum(network, apiKey, url)
4041
const estimateGas = data?.estimateGas ?? {
4142
from: '0xb4c9E4617a16Be36B92689b9e07e9F64757c1792',
4243
to: '0x4675C7e5BaAFBFFbca748158bEcBA61ef3b0a263',
@@ -49,23 +50,23 @@ export const EvmE2eUtils = {
4950
}
5051

5152
it('eth_gasPrice', async () => {
52-
const tatum = await EvmE2eUtils.initTatum(network, apiKey)
53+
const tatum = await EvmE2eUtils.initTatum(network, apiKey, url)
5354
const { result } = await tatum.rpc.gasPrice()
5455

5556
await tatum.destroy()
5657
expect(result?.toNumber()).toBeGreaterThan(0)
5758
})
5859

5960
it('web3_clientVersion', async () => {
60-
const tatum = await EvmE2eUtils.initTatum(network, apiKey)
61+
const tatum = await EvmE2eUtils.initTatum(network, apiKey, url)
6162
const { result } = await tatum.rpc.clientVersion()
6263

6364
await tatum.destroy()
6465
expect(result).toBeTruthy()
6566
})
6667

6768
it('eth_getBlockByNumber', async () => {
68-
const tatum = await EvmE2eUtils.initTatum(network, apiKey)
69+
const tatum = await EvmE2eUtils.initTatum(network, apiKey, url)
6970
const { result } = await tatum.rpc.blockNumber()
7071
const { result: block } = await tatum.rpc.getBlockByNumber((result as BigNumber).toNumber() - 1000)
7172
await tatum.destroy()

src/e2e/rpc/evm/evm.rpc.spec.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ const testNetworks = [
2020
},
2121
{ network: Network.FLARE },
2222
{ network: Network.FLARE_SONGBIRD },
23-
{ network: Network.FLARE_COSTON },
23+
// { network: Network.FLARE_COSTON },
2424
{ network: Network.FLARE_COSTON_2 },
2525
{ network: Network.ETHEREUM },
2626
{ network: Network.ETHEREUM_SEPOLIA },
2727
{ network: Network.ETHEREUM_HOLESKY },
28-
{ network: Network.FANTOM },
29-
{ network: Network.FANTOM_TESTNET, apiKey: process.env.V3_API_KEY_TESTNET },
28+
// { network: Network.FANTOM },
29+
// { network: Network.FANTOM_TESTNET, apiKey: process.env.V3_API_KEY_TESTNET },
3030
{ network: Network.ETHEREUM_CLASSIC },
3131
// { network: Network.POLYGON },
3232
{ network: Network.POLYGON_AMOY },
@@ -71,6 +71,8 @@ const testNetworks = [
7171
// { network: Network.CRONOS },
7272
{ network: Network.CRONOS_TESTNET, apiKey: process.env.V3_API_KEY_TESTNET },
7373
{ network: Network.BASE },
74+
{ network: Network.ZK_SYNC, url: 'https://mainnet.era.zksync.io' },
75+
{ network: Network.ZK_SYNC_TESTNET, url: 'https://sepolia.era.zksync.dev' },
7476
]
7577

7678
describe.each(testNetworks)('RPC EVM', (testNetwork) => {
+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Network, ZkSync } from '../../../service'
2+
import { EvmE2eUtils } from './evm.e2e.utils'
3+
4+
const run = async (network: Network, url: string) => {
5+
it('zks_getL1GasPrice', async () => {
6+
const tatum = await EvmE2eUtils.initTatum<ZkSync>(network, undefined, url)
7+
const { result } = await tatum.rpc.zksGetL1GasPrice()
8+
9+
await tatum.destroy()
10+
expect(result).toBeDefined()
11+
})
12+
13+
it('zks_getBlockDetails', async () => {
14+
const tatum = await EvmE2eUtils.initTatum<ZkSync>(network, undefined, url)
15+
const { result } = await tatum.rpc.zksGetBlockDetails(39830202)
16+
17+
await tatum.destroy()
18+
expect(result).toBeDefined()
19+
})
20+
21+
it('zks_getBaseTokenL1Address', async () => {
22+
const tatum = await EvmE2eUtils.initTatum<ZkSync>(network, undefined, url)
23+
const { result } = await tatum.rpc.zksGetBaseTokenL1Address()
24+
25+
await tatum.destroy()
26+
expect(result).toBeDefined()
27+
})
28+
29+
it('zks_getFeeParams', async () => {
30+
const tatum = await EvmE2eUtils.initTatum<ZkSync>(network, undefined, url)
31+
const { result } = await tatum.rpc.zksGetFeeParams()
32+
33+
await tatum.destroy()
34+
expect(result).toBeDefined()
35+
36+
})
37+
}
38+
39+
describe.each([
40+
{ network: Network.ZK_SYNC, url: 'https://mainnet.era.zksync.io' },
41+
{ network: Network.ZK_SYNC_TESTNET, url: 'https://sepolia.era.zksync.dev'},
42+
])('RPC ZkSync', (network) => {
43+
const { network: networkName, url } = network
44+
describe(networkName, () => {
45+
run(networkName, url)
46+
})
47+
})

0 commit comments

Comments
 (0)