@snowbridge/provider-viem 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+
2
+ 
3
+ > @snowbridge/provider-viem@1.0.0 build /Users/alistairsingh/c/snowbridge/web/packages/provider-viem
4
+ > tsc --build --force
5
+
@@ -0,0 +1,6 @@
1
+
2
+ 
3
+ > @snowbridge/provider-viem@1.0.0 format /Users/alistairsingh/c/snowbridge/web/packages/provider-viem
4
+ > prettier src --write
5
+
6
+ src/index.tssrc/index.ts 106ms (unchanged)
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # `@snowbridge/provider-viem`
2
+
3
+ `viem` implementation of the Snowbridge `EthereumProvider` interface.
@@ -0,0 +1,54 @@
1
+ import type { Abi, Address, Hex, PublicClient, TransactionReceipt, TransactionRequest } from "viem";
2
+ import type { DepositParamsStruct, EthereumProvider, EthereumProviderTypes, FeeData, GatewayV1OutboundMessageAccepted, GatewayV2OutboundMessageAccepted, IGatewayV1, IGatewayV2, L1AdapterDepositParams, L1LegacySwapRouterExactOutputSingleParams, L1SwapRouterExactOutputSingleParams, MultiAddressStruct, SendParamsStruct, SwapParamsStruct } from "@snowbridge/base-types";
3
+ export type ViemContractTransaction = TransactionRequest & {
4
+ account?: Address;
5
+ };
6
+ export type ViemContract = {
7
+ getAddress(): Promise<Address>;
8
+ removeAllListeners(): Promise<void>;
9
+ [key: string]: unknown;
10
+ };
11
+ export interface ViemProviderTypes extends EthereumProviderTypes {
12
+ Connection: PublicClient;
13
+ Contract: ViemContract;
14
+ Abi: Abi;
15
+ TransactionReceipt: TransactionReceipt;
16
+ ContractTransaction: ViemContractTransaction;
17
+ }
18
+ export declare class ViemEthereumProvider implements EthereumProvider<ViemProviderTypes> {
19
+ readonly providerTypes: ViemProviderTypes;
20
+ createProvider(url: string): PublicClient;
21
+ destroyProvider(provider: PublicClient): void;
22
+ destroyContract(_contract: ViemContract): Promise<void>;
23
+ connectContract(address: string, abi: Abi, provider: PublicClient): ViemContract;
24
+ erc20Balance(provider: PublicClient, tokenAddress: string, owner: string, spender: string): Promise<{
25
+ balance: bigint;
26
+ gatewayAllowance: bigint;
27
+ }>;
28
+ gatewayV1SendToken(_provider: PublicClient, gatewayAddress: string, sender: string, token: string, destinationChain: number, destinationAddress: MultiAddressStruct, destinationFee: bigint, amount: bigint, value: bigint): Promise<ViemContractTransaction>;
29
+ gatewayV2RegisterToken(_provider: PublicClient, gatewayAddress: string, sender: string, token: string, network: number, executionFee: bigint, relayerFee: bigint, value: bigint): Promise<ViemContractTransaction>;
30
+ gatewayV2CreateAgent(_provider: PublicClient, gatewayAddress: string, id: string): Promise<ViemContractTransaction>;
31
+ gatewayV2SendMessage(_provider: PublicClient, gatewayAddress: string, sender: string, xcm: Uint8Array, assets: string[], claimer: Uint8Array, executionFee: bigint, relayerFee: bigint, value: bigint): Promise<ViemContractTransaction>;
32
+ l2AdapterSendEtherAndCall(_provider: PublicClient, adapterAddress: string, sender: string, params: DepositParamsStruct, sendParams: SendParamsStruct, recipient: string, topic: string, value?: bigint): Promise<ViemContractTransaction>;
33
+ l2AdapterSendTokenAndCall(_provider: PublicClient, adapterAddress: string, sender: string, params: DepositParamsStruct, swapParams: SwapParamsStruct, sendParams: SendParamsStruct, recipient: string, topic: string): Promise<ViemContractTransaction>;
34
+ evmParachainTransferAssetsUsingTypeAndThenAddress(_provider: PublicClient, precompileAddress: string, sourceAccount: string, destination: [number, string[]], assets: [string, bigint][], assetsTransferType: number, remoteFeesIdIndex: number, feesTransferType: number, customXcmHex: string): Promise<ViemContractTransaction>;
35
+ encodeFunctionData(abi: Abi | readonly [string, ...string[]], method: string, args: readonly unknown[]): Hex;
36
+ decodeFunctionResult<T = unknown>(abi: Abi | readonly [string, ...string[]], method: string, data: string): T;
37
+ encodeNativeAsset(tokenAddress: string, amount: bigint): Hex;
38
+ l1AdapterDepositNativeEther(params: L1AdapterDepositParams, recipient: string, topic: string): Hex;
39
+ l1AdapterDepositToken(params: L1AdapterDepositParams, recipient: string, topic: string): Hex;
40
+ l1SwapRouterExactOutputSingle(params: L1SwapRouterExactOutputSingleParams): Hex;
41
+ l1LegacySwapRouterExactOutputSingle(params: L1LegacySwapRouterExactOutputSingleParams): Hex;
42
+ beneficiaryMultiAddress(beneficiary: string): MultiAddressStruct;
43
+ estimateGas(provider: PublicClient, tx: ViemContractTransaction): Promise<bigint>;
44
+ getTransactionCount(provider: PublicClient, address: string, blockTag?: "latest" | "pending"): Promise<number>;
45
+ getBalance(provider: PublicClient, address: string): Promise<bigint>;
46
+ getFeeData(provider: PublicClient): Promise<FeeData>;
47
+ parseUnits(value: string, decimals: number): bigint;
48
+ gatewayOperatingMode(gateway: ViemContract & (IGatewayV1 | IGatewayV2)): Promise<bigint>;
49
+ gatewayChannelOperatingModeOf(gateway: ViemContract & IGatewayV1, channelId: string): Promise<bigint>;
50
+ isContractAddress(provider: PublicClient, address: string): Promise<boolean>;
51
+ scanGatewayV1OutboundMessageAccepted(receipt: TransactionReceipt): GatewayV1OutboundMessageAccepted | null;
52
+ scanGatewayV2OutboundMessageAccepted(receipt: TransactionReceipt): GatewayV2OutboundMessageAccepted | null;
53
+ }
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,397 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ViemEthereumProvider = void 0;
4
+ const viem_1 = require("viem");
5
+ const base_types_1 = require("@snowbridge/base-types");
6
+ function toAddress(value) {
7
+ return (0, viem_1.getAddress)(value);
8
+ }
9
+ function asAbi(abi) {
10
+ if (Array.isArray(abi) && abi.every((item) => typeof item === "string")) {
11
+ return (0, viem_1.parseAbi)(abi);
12
+ }
13
+ return abi;
14
+ }
15
+ function toBytesHex(value) {
16
+ return typeof value === "string" ? value : (0, viem_1.toHex)(value);
17
+ }
18
+ function normalizeMultiAddress(address) {
19
+ return {
20
+ kind: address.kind,
21
+ data: address.data,
22
+ };
23
+ }
24
+ function normalizeDepositParams(params) {
25
+ return {
26
+ ...params,
27
+ inputToken: toAddress(params.inputToken),
28
+ outputToken: toAddress(params.outputToken),
29
+ };
30
+ }
31
+ function normalizeSendParams(sendParams) {
32
+ return {
33
+ xcm: toBytesHex(sendParams.xcm),
34
+ assets: sendParams.assets.map((asset) => asset),
35
+ claimer: toBytesHex(sendParams.claimer),
36
+ executionFee: sendParams.executionFee,
37
+ relayerFee: sendParams.relayerFee,
38
+ };
39
+ }
40
+ function normalizeSwapParams(swapParams) {
41
+ return {
42
+ ...swapParams,
43
+ router: toAddress(swapParams.router),
44
+ callData: swapParams.callData,
45
+ };
46
+ }
47
+ function normalizeDestination(destination) {
48
+ return [destination[0], destination[1].map((item) => item)];
49
+ }
50
+ function createReadOnlyContract(address, abi, provider) {
51
+ const normalizedAbi = asAbi(abi);
52
+ return new Proxy({
53
+ async getAddress() {
54
+ return address;
55
+ },
56
+ async removeAllListeners() { },
57
+ }, {
58
+ get(target, prop, receiver) {
59
+ if (typeof prop !== "string") {
60
+ return Reflect.get(target, prop, receiver);
61
+ }
62
+ if (prop in target) {
63
+ return Reflect.get(target, prop, receiver);
64
+ }
65
+ const fn = (async (...args) => {
66
+ return await provider.readContract({
67
+ address,
68
+ abi: normalizedAbi,
69
+ functionName: prop,
70
+ args,
71
+ });
72
+ });
73
+ fn.staticCall = async (...args) => {
74
+ const result = await provider.simulateContract({
75
+ address,
76
+ abi: normalizedAbi,
77
+ functionName: prop,
78
+ args,
79
+ });
80
+ return result.result;
81
+ };
82
+ return fn;
83
+ },
84
+ });
85
+ }
86
+ class ViemEthereumProvider {
87
+ createProvider(url) {
88
+ return (0, viem_1.createPublicClient)({
89
+ transport: url.startsWith("http") ? (0, viem_1.http)(url) : (0, viem_1.webSocket)(url),
90
+ });
91
+ }
92
+ destroyProvider(provider) {
93
+ const transport = provider.transport;
94
+ transport.value?.close?.();
95
+ }
96
+ async destroyContract(_contract) { }
97
+ connectContract(address, abi, provider) {
98
+ return createReadOnlyContract(toAddress(address), asAbi(abi), provider);
99
+ }
100
+ async erc20Balance(provider, tokenAddress, owner, spender) {
101
+ const [balance, gatewayAllowance] = await Promise.all([
102
+ provider.readContract({
103
+ address: toAddress(tokenAddress),
104
+ abi: asAbi(base_types_1.IERC20_ABI),
105
+ functionName: "balanceOf",
106
+ args: [toAddress(owner)],
107
+ }),
108
+ provider.readContract({
109
+ address: toAddress(tokenAddress),
110
+ abi: asAbi(base_types_1.IERC20_ABI),
111
+ functionName: "allowance",
112
+ args: [toAddress(owner), toAddress(spender)],
113
+ }),
114
+ ]);
115
+ return {
116
+ balance: balance,
117
+ gatewayAllowance: gatewayAllowance,
118
+ };
119
+ }
120
+ async gatewayV1SendToken(_provider, gatewayAddress, sender, token, destinationChain, destinationAddress, destinationFee, amount, value) {
121
+ return {
122
+ to: toAddress(gatewayAddress),
123
+ account: toAddress(sender),
124
+ value,
125
+ data: this.encodeFunctionData(asAbi(base_types_1.IGATEWAY_V1_ABI), "sendToken", [
126
+ toAddress(token),
127
+ BigInt(destinationChain),
128
+ normalizeMultiAddress(destinationAddress),
129
+ destinationFee,
130
+ amount,
131
+ ]),
132
+ };
133
+ }
134
+ async gatewayV2RegisterToken(_provider, gatewayAddress, sender, token, network, executionFee, relayerFee, value) {
135
+ return {
136
+ to: toAddress(gatewayAddress),
137
+ account: toAddress(sender),
138
+ value,
139
+ data: this.encodeFunctionData(asAbi(base_types_1.IGATEWAY_V2_ABI), "v2_registerToken", [toAddress(token), BigInt(network), executionFee, relayerFee]),
140
+ };
141
+ }
142
+ async gatewayV2CreateAgent(_provider, gatewayAddress, id) {
143
+ return {
144
+ to: toAddress(gatewayAddress),
145
+ data: this.encodeFunctionData(asAbi(base_types_1.IGATEWAY_V2_ABI), "v2_createAgent", [
146
+ id,
147
+ ]),
148
+ };
149
+ }
150
+ async gatewayV2SendMessage(_provider, gatewayAddress, sender, xcm, assets, claimer, executionFee, relayerFee, value) {
151
+ return {
152
+ to: toAddress(gatewayAddress),
153
+ account: toAddress(sender),
154
+ value,
155
+ data: this.encodeFunctionData(asAbi(base_types_1.IGATEWAY_V2_ABI), "v2_sendMessage", [
156
+ toBytesHex(xcm),
157
+ assets.map((asset) => asset),
158
+ toBytesHex(claimer),
159
+ executionFee,
160
+ relayerFee,
161
+ ]),
162
+ };
163
+ }
164
+ async l2AdapterSendEtherAndCall(_provider, adapterAddress, sender, params, sendParams, recipient, topic, value) {
165
+ return {
166
+ to: toAddress(adapterAddress),
167
+ account: toAddress(sender),
168
+ value,
169
+ data: this.encodeFunctionData(asAbi(base_types_1.SNOWBRIDGE_L2_ADAPTOR_ABI), "sendEtherAndCall", [
170
+ normalizeDepositParams(params),
171
+ normalizeSendParams(sendParams),
172
+ toAddress(recipient),
173
+ topic,
174
+ ]),
175
+ };
176
+ }
177
+ async l2AdapterSendTokenAndCall(_provider, adapterAddress, sender, params, swapParams, sendParams, recipient, topic) {
178
+ return {
179
+ to: toAddress(adapterAddress),
180
+ account: toAddress(sender),
181
+ data: this.encodeFunctionData(asAbi(base_types_1.SNOWBRIDGE_L2_ADAPTOR_ABI), "sendTokenAndCall", [
182
+ normalizeDepositParams(params),
183
+ normalizeSwapParams(swapParams),
184
+ normalizeSendParams(sendParams),
185
+ toAddress(recipient),
186
+ topic,
187
+ ]),
188
+ };
189
+ }
190
+ async evmParachainTransferAssetsUsingTypeAndThenAddress(_provider, precompileAddress, sourceAccount, destination, assets, assetsTransferType, remoteFeesIdIndex, feesTransferType, customXcmHex) {
191
+ return {
192
+ to: toAddress(precompileAddress),
193
+ account: toAddress(sourceAccount),
194
+ data: this.encodeFunctionData(asAbi(base_types_1.MOONBEAM_PALLET_XCM_PRECOMPILE_ABI), "transferAssetsUsingTypeAndThenAddress", [
195
+ normalizeDestination(destination),
196
+ assets.map(([asset, amount]) => [toAddress(asset), amount]),
197
+ assetsTransferType,
198
+ remoteFeesIdIndex,
199
+ feesTransferType,
200
+ customXcmHex,
201
+ ]),
202
+ };
203
+ }
204
+ encodeFunctionData(abi, method, args) {
205
+ return (0, viem_1.encodeFunctionData)({
206
+ abi: asAbi(abi),
207
+ functionName: method,
208
+ args: [...args],
209
+ });
210
+ }
211
+ decodeFunctionResult(abi, method, data) {
212
+ return (0, viem_1.decodeFunctionResult)({
213
+ abi: asAbi(abi),
214
+ functionName: method,
215
+ data: data,
216
+ });
217
+ }
218
+ encodeNativeAsset(tokenAddress, amount) {
219
+ return (0, viem_1.encodeAbiParameters)((0, viem_1.parseAbiParameters)("uint8,address,uint128"), [
220
+ 0,
221
+ toAddress(tokenAddress),
222
+ amount,
223
+ ]);
224
+ }
225
+ l1AdapterDepositNativeEther(params, recipient, topic) {
226
+ return this.encodeFunctionData(asAbi(base_types_1.SNOWBRIDGE_L1_ADAPTOR_ABI), "depositNativeEther", [normalizeDepositParams(params), toAddress(recipient), topic]);
227
+ }
228
+ l1AdapterDepositToken(params, recipient, topic) {
229
+ return this.encodeFunctionData(asAbi(base_types_1.SNOWBRIDGE_L1_ADAPTOR_ABI), "depositToken", [normalizeDepositParams(params), toAddress(recipient), topic]);
230
+ }
231
+ l1SwapRouterExactOutputSingle(params) {
232
+ return this.encodeFunctionData(asAbi(base_types_1.SWAP_ROUTER_ABI), "exactOutputSingle", [
233
+ {
234
+ ...params,
235
+ tokenIn: toAddress(params.tokenIn),
236
+ tokenOut: toAddress(params.tokenOut),
237
+ recipient: toAddress(params.recipient),
238
+ },
239
+ ]);
240
+ }
241
+ l1LegacySwapRouterExactOutputSingle(params) {
242
+ return this.encodeFunctionData(asAbi(base_types_1.SWAP_LEGACY_ROUTER_ABI), "exactOutputSingle", [
243
+ {
244
+ ...params,
245
+ tokenIn: toAddress(params.tokenIn),
246
+ tokenOut: toAddress(params.tokenOut),
247
+ recipient: toAddress(params.recipient),
248
+ },
249
+ ]);
250
+ }
251
+ beneficiaryMultiAddress(beneficiary) {
252
+ let kind;
253
+ if (/^0x[a-fA-F0-9]{40}$/.test(beneficiary)) {
254
+ kind = 2;
255
+ }
256
+ else if (/^0x[a-fA-F0-9]{64}$/.test(beneficiary)) {
257
+ kind = 1;
258
+ }
259
+ else {
260
+ throw new Error("Unknown Beneficiary address format.");
261
+ }
262
+ let data;
263
+ switch (kind) {
264
+ case 1:
265
+ data = (0, viem_1.encodeAbiParameters)((0, viem_1.parseAbiParameters)("bytes32"), [
266
+ beneficiary,
267
+ ]);
268
+ break;
269
+ case 2:
270
+ data = (0, viem_1.encodeAbiParameters)((0, viem_1.parseAbiParameters)("bytes20"), [
271
+ beneficiary,
272
+ ]);
273
+ break;
274
+ default:
275
+ throw new Error(`Unknown Beneficiary kind ${kind}.`);
276
+ }
277
+ return { kind, data };
278
+ }
279
+ async estimateGas(provider, tx) {
280
+ return await provider.estimateGas(tx);
281
+ }
282
+ async getTransactionCount(provider, address, blockTag = "latest") {
283
+ return Number(await provider.getTransactionCount({
284
+ address: toAddress(address),
285
+ blockTag,
286
+ }));
287
+ }
288
+ async getBalance(provider, address) {
289
+ return await provider.getBalance({ address: toAddress(address) });
290
+ }
291
+ async getFeeData(provider) {
292
+ const gasPrice = await provider.getGasPrice();
293
+ try {
294
+ const fees = await provider.estimateFeesPerGas();
295
+ return {
296
+ gasPrice: fees.gasPrice ?? gasPrice,
297
+ maxFeePerGas: fees.maxFeePerGas ?? null,
298
+ maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? null,
299
+ };
300
+ }
301
+ catch {
302
+ return {
303
+ gasPrice,
304
+ maxFeePerGas: null,
305
+ maxPriorityFeePerGas: null,
306
+ };
307
+ }
308
+ }
309
+ parseUnits(value, decimals) {
310
+ return (0, viem_1.parseUnits)(value, decimals);
311
+ }
312
+ async gatewayOperatingMode(gateway) {
313
+ return BigInt(await gateway.operatingMode());
314
+ }
315
+ async gatewayChannelOperatingModeOf(gateway, channelId) {
316
+ return BigInt(await gateway.channelOperatingModeOf(channelId));
317
+ }
318
+ async isContractAddress(provider, address) {
319
+ if (!/^0x[a-fA-F0-9]{40}$/.test(address)) {
320
+ return false;
321
+ }
322
+ try {
323
+ const code = await provider.getCode({ address: toAddress(address) });
324
+ return code !== undefined && code !== "0x";
325
+ }
326
+ catch {
327
+ return false;
328
+ }
329
+ }
330
+ scanGatewayV1OutboundMessageAccepted(receipt) {
331
+ for (const log of receipt.logs) {
332
+ try {
333
+ const event = (0, viem_1.decodeEventLog)({
334
+ abi: asAbi(base_types_1.IGATEWAY_V1_ABI),
335
+ topics: log.topics,
336
+ data: log.data,
337
+ });
338
+ if (event.eventName === "OutboundMessageAccepted") {
339
+ const args = event.args;
340
+ if (!args) {
341
+ continue;
342
+ }
343
+ return {
344
+ channelId: String(args[0]),
345
+ nonce: BigInt(args[1]),
346
+ messageId: String(args[2]),
347
+ blockHash: receipt.blockHash,
348
+ blockNumber: Number(receipt.blockNumber),
349
+ txHash: receipt.transactionHash,
350
+ txIndex: Number(receipt.transactionIndex),
351
+ };
352
+ }
353
+ }
354
+ catch { }
355
+ }
356
+ return null;
357
+ }
358
+ scanGatewayV2OutboundMessageAccepted(receipt) {
359
+ for (const log of receipt.logs) {
360
+ try {
361
+ const event = (0, viem_1.decodeEventLog)({
362
+ abi: asAbi(base_types_1.IGATEWAY_V2_ABI),
363
+ topics: log.topics,
364
+ data: log.data,
365
+ });
366
+ if (event.eventName === "OutboundMessageAccepted") {
367
+ const args = event.args;
368
+ if (!args) {
369
+ continue;
370
+ }
371
+ return {
372
+ nonce: BigInt(args.nonce),
373
+ payload: {
374
+ origin: args.payload.origin,
375
+ assets: args.payload.assets.map((asset) => [
376
+ Number(asset.kind),
377
+ asset.data,
378
+ ]),
379
+ xcm: [Number(args.payload.xcm.kind), args.payload.xcm.data],
380
+ claimer: args.payload.claimer,
381
+ value: BigInt(args.payload.value),
382
+ executionFee: BigInt(args.payload.executionFee),
383
+ relayerFee: BigInt(args.payload.relayerFee),
384
+ },
385
+ blockHash: receipt.blockHash,
386
+ blockNumber: Number(receipt.blockNumber),
387
+ txHash: receipt.transactionHash,
388
+ txIndex: Number(receipt.transactionIndex),
389
+ };
390
+ }
391
+ }
392
+ catch { }
393
+ }
394
+ return null;
395
+ }
396
+ }
397
+ exports.ViemEthereumProvider = ViemEthereumProvider;
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@snowbridge/provider-viem",
3
+ "version": "1.0.0",
4
+ "description": "Snowbridge viem provider implementation",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/Snowfork/snowbridge.git",
9
+ "directory": "web/packages/provider-viem"
10
+ },
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
+ "devDependencies": {
14
+ "@types/node": "24.6.2",
15
+ "@typescript-eslint/eslint-plugin": "8.45.0",
16
+ "@typescript-eslint/parser": "8.45.0",
17
+ "eslint": "9.37.0",
18
+ "eslint-config-prettier": "10.1.8",
19
+ "prettier": "3.6.2",
20
+ "ts-node": "10.9.2",
21
+ "tsconfig-paths": "4.2.0",
22
+ "typescript": "5.9.3"
23
+ },
24
+ "dependencies": {
25
+ "viem": "^2.38.5",
26
+ "@snowbridge/base-types": "1.0.0"
27
+ },
28
+ "scripts": {
29
+ "build": "tsc --build --force",
30
+ "lint": "eslint .",
31
+ "format": "prettier src --write"
32
+ }
33
+ }
package/src/index.ts ADDED
@@ -0,0 +1,685 @@
1
+ import {
2
+ createPublicClient,
3
+ decodeEventLog,
4
+ decodeFunctionResult,
5
+ encodeAbiParameters,
6
+ encodeFunctionData,
7
+ getAddress,
8
+ http,
9
+ parseAbi,
10
+ parseAbiParameters,
11
+ parseUnits,
12
+ toHex,
13
+ webSocket,
14
+ } from "viem";
15
+ import type {
16
+ Abi,
17
+ Address,
18
+ Hex,
19
+ Log,
20
+ PublicClient,
21
+ TransactionReceipt,
22
+ TransactionRequest,
23
+ } from "viem";
24
+ import type {
25
+ BeefyClient,
26
+ DepositParamsStruct,
27
+ EthereumProvider,
28
+ EthereumProviderTypes,
29
+ FeeData,
30
+ GatewayV1OutboundMessageAccepted,
31
+ GatewayV2OutboundMessageAccepted,
32
+ IGatewayV1,
33
+ IGatewayV2,
34
+ IERC20,
35
+ ISwapQuoter,
36
+ L1AdapterDepositParams,
37
+ L1LegacySwapRouterExactOutputSingleParams,
38
+ L1SwapRouterExactOutputSingleParams,
39
+ MultiAddressStruct,
40
+ SendParamsStruct,
41
+ SwapParamsStruct,
42
+ } from "@snowbridge/base-types";
43
+ import {
44
+ IERC20_ABI,
45
+ IGATEWAY_V1_ABI,
46
+ IGATEWAY_V2_ABI,
47
+ MOONBEAM_PALLET_XCM_PRECOMPILE_ABI,
48
+ SNOWBRIDGE_L1_ADAPTOR_ABI,
49
+ SNOWBRIDGE_L2_ADAPTOR_ABI,
50
+ SWAP_LEGACY_ROUTER_ABI,
51
+ SWAP_ROUTER_ABI,
52
+ } from "@snowbridge/base-types";
53
+
54
+ type ReadonlyFunction = ((...args: unknown[]) => Promise<unknown>) & {
55
+ staticCall: (...args: unknown[]) => Promise<unknown>;
56
+ };
57
+
58
+ export type ViemContractTransaction = TransactionRequest & {
59
+ account?: Address;
60
+ };
61
+
62
+ export type ViemContract = {
63
+ getAddress(): Promise<Address>;
64
+ removeAllListeners(): Promise<void>;
65
+ [key: string]: unknown;
66
+ };
67
+
68
+ export interface ViemProviderTypes extends EthereumProviderTypes {
69
+ Connection: PublicClient;
70
+ Contract: ViemContract;
71
+ Abi: Abi;
72
+ TransactionReceipt: TransactionReceipt;
73
+ ContractTransaction: ViemContractTransaction;
74
+ }
75
+
76
+ function toAddress(value: string): Address {
77
+ return getAddress(value);
78
+ }
79
+
80
+ function asAbi<TAbi extends Abi>(abi: TAbi): TAbi;
81
+ function asAbi(abi: readonly [string, ...string[]]): Abi;
82
+ function asAbi(abi: Abi | readonly [string, ...string[]]): Abi;
83
+ function asAbi(abi: Abi | readonly [string, ...string[]]): Abi {
84
+ if (Array.isArray(abi) && abi.every((item) => typeof item === "string")) {
85
+ return parseAbi(abi);
86
+ }
87
+ return abi as Abi;
88
+ }
89
+
90
+ function toBytesHex(value: string | Uint8Array): Hex {
91
+ return typeof value === "string" ? (value as Hex) : toHex(value);
92
+ }
93
+
94
+ function normalizeMultiAddress(
95
+ address: MultiAddressStruct,
96
+ ): MultiAddressStruct {
97
+ return {
98
+ kind: address.kind,
99
+ data: address.data as Hex,
100
+ };
101
+ }
102
+
103
+ function normalizeDepositParams<
104
+ T extends { inputToken: string; outputToken: string },
105
+ >(params: T): T {
106
+ return {
107
+ ...params,
108
+ inputToken: toAddress(params.inputToken),
109
+ outputToken: toAddress(params.outputToken),
110
+ };
111
+ }
112
+
113
+ function normalizeSendParams(sendParams: SendParamsStruct): {
114
+ xcm: Hex;
115
+ assets: Hex[];
116
+ claimer: Hex;
117
+ executionFee: bigint;
118
+ relayerFee: bigint;
119
+ } {
120
+ return {
121
+ xcm: toBytesHex(sendParams.xcm),
122
+ assets: sendParams.assets.map((asset) => asset as Hex),
123
+ claimer: toBytesHex(sendParams.claimer),
124
+ executionFee: sendParams.executionFee,
125
+ relayerFee: sendParams.relayerFee,
126
+ };
127
+ }
128
+
129
+ function normalizeSwapParams(swapParams: SwapParamsStruct): SwapParamsStruct & {
130
+ callData: Hex;
131
+ } {
132
+ return {
133
+ ...swapParams,
134
+ router: toAddress(swapParams.router),
135
+ callData: swapParams.callData as Hex,
136
+ };
137
+ }
138
+
139
+ function normalizeDestination(
140
+ destination: [number, string[]],
141
+ ): [number, Hex[]] {
142
+ return [destination[0], destination[1].map((item) => item as Hex)];
143
+ }
144
+
145
+ function createReadOnlyContract(
146
+ address: Address,
147
+ abi: Abi | readonly [string, ...string[]],
148
+ provider: PublicClient,
149
+ ): ViemContract {
150
+ const normalizedAbi = asAbi(abi);
151
+ return new Proxy(
152
+ {
153
+ async getAddress() {
154
+ return address;
155
+ },
156
+ async removeAllListeners() {},
157
+ } as ViemContract,
158
+ {
159
+ get(target, prop, receiver) {
160
+ if (typeof prop !== "string") {
161
+ return Reflect.get(target, prop, receiver);
162
+ }
163
+ if (prop in target) {
164
+ return Reflect.get(target, prop, receiver);
165
+ }
166
+
167
+ const fn = (async (...args: unknown[]) => {
168
+ return await provider.readContract({
169
+ address,
170
+ abi: normalizedAbi,
171
+ functionName: prop,
172
+ args,
173
+ } as never);
174
+ }) as ReadonlyFunction;
175
+
176
+ fn.staticCall = async (...args: unknown[]) => {
177
+ const result = await provider.simulateContract({
178
+ address,
179
+ abi: normalizedAbi,
180
+ functionName: prop,
181
+ args,
182
+ } as never);
183
+ return result.result;
184
+ };
185
+
186
+ return fn;
187
+ },
188
+ },
189
+ );
190
+ }
191
+
192
+ export class ViemEthereumProvider
193
+ implements EthereumProvider<ViemProviderTypes>
194
+ {
195
+ declare readonly providerTypes: ViemProviderTypes;
196
+
197
+ createProvider(url: string): PublicClient {
198
+ return createPublicClient({
199
+ transport: url.startsWith("http") ? http(url) : webSocket(url),
200
+ });
201
+ }
202
+
203
+ destroyProvider(provider: PublicClient): void {
204
+ const transport = provider.transport as { value?: { close?: () => void } };
205
+ transport.value?.close?.();
206
+ }
207
+
208
+ async destroyContract(_contract: ViemContract): Promise<void> {}
209
+
210
+ connectContract(
211
+ address: string,
212
+ abi: Abi,
213
+ provider: PublicClient,
214
+ ): ViemContract {
215
+ return createReadOnlyContract(toAddress(address), asAbi(abi), provider);
216
+ }
217
+
218
+ async erc20Balance(
219
+ provider: PublicClient,
220
+ tokenAddress: string,
221
+ owner: string,
222
+ spender: string,
223
+ ): Promise<{ balance: bigint; gatewayAllowance: bigint }> {
224
+ const [balance, gatewayAllowance] = await Promise.all([
225
+ provider.readContract({
226
+ address: toAddress(tokenAddress),
227
+ abi: asAbi(IERC20_ABI),
228
+ functionName: "balanceOf",
229
+ args: [toAddress(owner)],
230
+ }),
231
+ provider.readContract({
232
+ address: toAddress(tokenAddress),
233
+ abi: asAbi(IERC20_ABI),
234
+ functionName: "allowance",
235
+ args: [toAddress(owner), toAddress(spender)],
236
+ }),
237
+ ]);
238
+ return {
239
+ balance: balance as bigint,
240
+ gatewayAllowance: gatewayAllowance as bigint,
241
+ };
242
+ }
243
+
244
+ async gatewayV1SendToken(
245
+ _provider: PublicClient,
246
+ gatewayAddress: string,
247
+ sender: string,
248
+ token: string,
249
+ destinationChain: number,
250
+ destinationAddress: MultiAddressStruct,
251
+ destinationFee: bigint,
252
+ amount: bigint,
253
+ value: bigint,
254
+ ): Promise<ViemContractTransaction> {
255
+ return {
256
+ to: toAddress(gatewayAddress),
257
+ account: toAddress(sender),
258
+ value,
259
+ data: this.encodeFunctionData(asAbi(IGATEWAY_V1_ABI), "sendToken", [
260
+ toAddress(token),
261
+ BigInt(destinationChain),
262
+ normalizeMultiAddress(destinationAddress),
263
+ destinationFee,
264
+ amount,
265
+ ]),
266
+ };
267
+ }
268
+
269
+ async gatewayV2RegisterToken(
270
+ _provider: PublicClient,
271
+ gatewayAddress: string,
272
+ sender: string,
273
+ token: string,
274
+ network: number,
275
+ executionFee: bigint,
276
+ relayerFee: bigint,
277
+ value: bigint,
278
+ ): Promise<ViemContractTransaction> {
279
+ return {
280
+ to: toAddress(gatewayAddress),
281
+ account: toAddress(sender),
282
+ value,
283
+ data: this.encodeFunctionData(
284
+ asAbi(IGATEWAY_V2_ABI),
285
+ "v2_registerToken",
286
+ [toAddress(token), BigInt(network), executionFee, relayerFee],
287
+ ),
288
+ };
289
+ }
290
+
291
+ async gatewayV2CreateAgent(
292
+ _provider: PublicClient,
293
+ gatewayAddress: string,
294
+ id: string,
295
+ ): Promise<ViemContractTransaction> {
296
+ return {
297
+ to: toAddress(gatewayAddress),
298
+ data: this.encodeFunctionData(asAbi(IGATEWAY_V2_ABI), "v2_createAgent", [
299
+ id as Hex,
300
+ ]),
301
+ };
302
+ }
303
+
304
+ async gatewayV2SendMessage(
305
+ _provider: PublicClient,
306
+ gatewayAddress: string,
307
+ sender: string,
308
+ xcm: Uint8Array,
309
+ assets: string[],
310
+ claimer: Uint8Array,
311
+ executionFee: bigint,
312
+ relayerFee: bigint,
313
+ value: bigint,
314
+ ): Promise<ViemContractTransaction> {
315
+ return {
316
+ to: toAddress(gatewayAddress),
317
+ account: toAddress(sender),
318
+ value,
319
+ data: this.encodeFunctionData(asAbi(IGATEWAY_V2_ABI), "v2_sendMessage", [
320
+ toBytesHex(xcm),
321
+ assets.map((asset) => asset as Hex),
322
+ toBytesHex(claimer),
323
+ executionFee,
324
+ relayerFee,
325
+ ]),
326
+ };
327
+ }
328
+
329
+ async l2AdapterSendEtherAndCall(
330
+ _provider: PublicClient,
331
+ adapterAddress: string,
332
+ sender: string,
333
+ params: DepositParamsStruct,
334
+ sendParams: SendParamsStruct,
335
+ recipient: string,
336
+ topic: string,
337
+ value?: bigint,
338
+ ): Promise<ViemContractTransaction> {
339
+ return {
340
+ to: toAddress(adapterAddress),
341
+ account: toAddress(sender),
342
+ value,
343
+ data: this.encodeFunctionData(
344
+ asAbi(SNOWBRIDGE_L2_ADAPTOR_ABI),
345
+ "sendEtherAndCall",
346
+ [
347
+ normalizeDepositParams(params),
348
+ normalizeSendParams(sendParams),
349
+ toAddress(recipient),
350
+ topic as Hex,
351
+ ],
352
+ ),
353
+ };
354
+ }
355
+
356
+ async l2AdapterSendTokenAndCall(
357
+ _provider: PublicClient,
358
+ adapterAddress: string,
359
+ sender: string,
360
+ params: DepositParamsStruct,
361
+ swapParams: SwapParamsStruct,
362
+ sendParams: SendParamsStruct,
363
+ recipient: string,
364
+ topic: string,
365
+ ): Promise<ViemContractTransaction> {
366
+ return {
367
+ to: toAddress(adapterAddress),
368
+ account: toAddress(sender),
369
+ data: this.encodeFunctionData(
370
+ asAbi(SNOWBRIDGE_L2_ADAPTOR_ABI),
371
+ "sendTokenAndCall",
372
+ [
373
+ normalizeDepositParams(params),
374
+ normalizeSwapParams(swapParams),
375
+ normalizeSendParams(sendParams),
376
+ toAddress(recipient),
377
+ topic as Hex,
378
+ ],
379
+ ),
380
+ };
381
+ }
382
+
383
+ async evmParachainTransferAssetsUsingTypeAndThenAddress(
384
+ _provider: PublicClient,
385
+ precompileAddress: string,
386
+ sourceAccount: string,
387
+ destination: [number, string[]],
388
+ assets: [string, bigint][],
389
+ assetsTransferType: number,
390
+ remoteFeesIdIndex: number,
391
+ feesTransferType: number,
392
+ customXcmHex: string,
393
+ ): Promise<ViemContractTransaction> {
394
+ return {
395
+ to: toAddress(precompileAddress),
396
+ account: toAddress(sourceAccount),
397
+ data: this.encodeFunctionData(
398
+ asAbi(MOONBEAM_PALLET_XCM_PRECOMPILE_ABI),
399
+ "transferAssetsUsingTypeAndThenAddress",
400
+ [
401
+ normalizeDestination(destination),
402
+ assets.map(([asset, amount]) => [toAddress(asset), amount]),
403
+ assetsTransferType,
404
+ remoteFeesIdIndex,
405
+ feesTransferType,
406
+ customXcmHex as Hex,
407
+ ],
408
+ ),
409
+ };
410
+ }
411
+
412
+ encodeFunctionData(
413
+ abi: Abi | readonly [string, ...string[]],
414
+ method: string,
415
+ args: readonly unknown[],
416
+ ): Hex {
417
+ return encodeFunctionData({
418
+ abi: asAbi(abi),
419
+ functionName: method,
420
+ args: [...args],
421
+ } as never);
422
+ }
423
+
424
+ decodeFunctionResult<T = unknown>(
425
+ abi: Abi | readonly [string, ...string[]],
426
+ method: string,
427
+ data: string,
428
+ ): T {
429
+ return decodeFunctionResult({
430
+ abi: asAbi(abi),
431
+ functionName: method,
432
+ data: data as Hex,
433
+ } as never) as T;
434
+ }
435
+
436
+ encodeNativeAsset(tokenAddress: string, amount: bigint): Hex {
437
+ return encodeAbiParameters(parseAbiParameters("uint8,address,uint128"), [
438
+ 0,
439
+ toAddress(tokenAddress),
440
+ amount,
441
+ ]);
442
+ }
443
+
444
+ l1AdapterDepositNativeEther(
445
+ params: L1AdapterDepositParams,
446
+ recipient: string,
447
+ topic: string,
448
+ ): Hex {
449
+ return this.encodeFunctionData(
450
+ asAbi(SNOWBRIDGE_L1_ADAPTOR_ABI),
451
+ "depositNativeEther",
452
+ [normalizeDepositParams(params), toAddress(recipient), topic as Hex],
453
+ );
454
+ }
455
+
456
+ l1AdapterDepositToken(
457
+ params: L1AdapterDepositParams,
458
+ recipient: string,
459
+ topic: string,
460
+ ): Hex {
461
+ return this.encodeFunctionData(
462
+ asAbi(SNOWBRIDGE_L1_ADAPTOR_ABI),
463
+ "depositToken",
464
+ [normalizeDepositParams(params), toAddress(recipient), topic as Hex],
465
+ );
466
+ }
467
+
468
+ l1SwapRouterExactOutputSingle(
469
+ params: L1SwapRouterExactOutputSingleParams,
470
+ ): Hex {
471
+ return this.encodeFunctionData(
472
+ asAbi(SWAP_ROUTER_ABI),
473
+ "exactOutputSingle",
474
+ [
475
+ {
476
+ ...params,
477
+ tokenIn: toAddress(params.tokenIn),
478
+ tokenOut: toAddress(params.tokenOut),
479
+ recipient: toAddress(params.recipient),
480
+ },
481
+ ],
482
+ );
483
+ }
484
+
485
+ l1LegacySwapRouterExactOutputSingle(
486
+ params: L1LegacySwapRouterExactOutputSingleParams,
487
+ ): Hex {
488
+ return this.encodeFunctionData(
489
+ asAbi(SWAP_LEGACY_ROUTER_ABI),
490
+ "exactOutputSingle",
491
+ [
492
+ {
493
+ ...params,
494
+ tokenIn: toAddress(params.tokenIn),
495
+ tokenOut: toAddress(params.tokenOut),
496
+ recipient: toAddress(params.recipient),
497
+ },
498
+ ],
499
+ );
500
+ }
501
+
502
+ beneficiaryMultiAddress(beneficiary: string): MultiAddressStruct {
503
+ let kind: number;
504
+ if (/^0x[a-fA-F0-9]{40}$/.test(beneficiary)) {
505
+ kind = 2;
506
+ } else if (/^0x[a-fA-F0-9]{64}$/.test(beneficiary)) {
507
+ kind = 1;
508
+ } else {
509
+ throw new Error("Unknown Beneficiary address format.");
510
+ }
511
+ let data: Hex;
512
+ switch (kind) {
513
+ case 1:
514
+ data = encodeAbiParameters(parseAbiParameters("bytes32"), [
515
+ beneficiary as Hex,
516
+ ]);
517
+ break;
518
+ case 2:
519
+ data = encodeAbiParameters(parseAbiParameters("bytes20"), [
520
+ beneficiary as Hex,
521
+ ]);
522
+ break;
523
+ default:
524
+ throw new Error(`Unknown Beneficiary kind ${kind}.`);
525
+ }
526
+ return { kind, data };
527
+ }
528
+
529
+ async estimateGas(
530
+ provider: PublicClient,
531
+ tx: ViemContractTransaction,
532
+ ): Promise<bigint> {
533
+ return await provider.estimateGas(tx);
534
+ }
535
+
536
+ async getTransactionCount(
537
+ provider: PublicClient,
538
+ address: string,
539
+ blockTag: "latest" | "pending" = "latest",
540
+ ): Promise<number> {
541
+ return Number(
542
+ await provider.getTransactionCount({
543
+ address: toAddress(address),
544
+ blockTag,
545
+ }),
546
+ );
547
+ }
548
+
549
+ async getBalance(provider: PublicClient, address: string): Promise<bigint> {
550
+ return await provider.getBalance({ address: toAddress(address) });
551
+ }
552
+
553
+ async getFeeData(provider: PublicClient): Promise<FeeData> {
554
+ const gasPrice = await provider.getGasPrice();
555
+ try {
556
+ const fees = await provider.estimateFeesPerGas();
557
+ return {
558
+ gasPrice: fees.gasPrice ?? gasPrice,
559
+ maxFeePerGas: fees.maxFeePerGas ?? null,
560
+ maxPriorityFeePerGas: fees.maxPriorityFeePerGas ?? null,
561
+ };
562
+ } catch {
563
+ return {
564
+ gasPrice,
565
+ maxFeePerGas: null,
566
+ maxPriorityFeePerGas: null,
567
+ };
568
+ }
569
+ }
570
+
571
+ parseUnits(value: string, decimals: number): bigint {
572
+ return parseUnits(value, decimals);
573
+ }
574
+
575
+ async gatewayOperatingMode(
576
+ gateway: ViemContract & (IGatewayV1 | IGatewayV2),
577
+ ): Promise<bigint> {
578
+ return BigInt(await gateway.operatingMode());
579
+ }
580
+
581
+ async gatewayChannelOperatingModeOf(
582
+ gateway: ViemContract & IGatewayV1,
583
+ channelId: string,
584
+ ): Promise<bigint> {
585
+ return BigInt(await gateway.channelOperatingModeOf(channelId));
586
+ }
587
+
588
+ async isContractAddress(
589
+ provider: PublicClient,
590
+ address: string,
591
+ ): Promise<boolean> {
592
+ if (!/^0x[a-fA-F0-9]{40}$/.test(address)) {
593
+ return false;
594
+ }
595
+ try {
596
+ const code = await provider.getCode({ address: toAddress(address) });
597
+ return code !== undefined && code !== "0x";
598
+ } catch {
599
+ return false;
600
+ }
601
+ }
602
+
603
+ scanGatewayV1OutboundMessageAccepted(
604
+ receipt: TransactionReceipt,
605
+ ): GatewayV1OutboundMessageAccepted | null {
606
+ for (const log of receipt.logs as Log[]) {
607
+ try {
608
+ const event = decodeEventLog({
609
+ abi: asAbi(IGATEWAY_V1_ABI),
610
+ topics: log.topics,
611
+ data: log.data,
612
+ });
613
+ if (event.eventName === "OutboundMessageAccepted") {
614
+ const args = event.args as unknown as readonly unknown[] | undefined;
615
+ if (!args) {
616
+ continue;
617
+ }
618
+ return {
619
+ channelId: String(args[0]),
620
+ nonce: BigInt(args[1] as bigint),
621
+ messageId: String(args[2]),
622
+ blockHash: receipt.blockHash,
623
+ blockNumber: Number(receipt.blockNumber),
624
+ txHash: receipt.transactionHash,
625
+ txIndex: Number(receipt.transactionIndex),
626
+ };
627
+ }
628
+ } catch {}
629
+ }
630
+ return null;
631
+ }
632
+
633
+ scanGatewayV2OutboundMessageAccepted(
634
+ receipt: TransactionReceipt,
635
+ ): GatewayV2OutboundMessageAccepted | null {
636
+ for (const log of receipt.logs as Log[]) {
637
+ try {
638
+ const event = decodeEventLog({
639
+ abi: asAbi(IGATEWAY_V2_ABI),
640
+ topics: log.topics,
641
+ data: log.data,
642
+ });
643
+ if (event.eventName === "OutboundMessageAccepted") {
644
+ const args = event.args as unknown as
645
+ | {
646
+ nonce: bigint;
647
+ payload: {
648
+ origin: Address;
649
+ assets: { kind: number; data: Hex }[];
650
+ xcm: { kind: number; data: Hex };
651
+ claimer: Hex;
652
+ value: bigint;
653
+ executionFee: bigint;
654
+ relayerFee: bigint;
655
+ };
656
+ }
657
+ | undefined;
658
+ if (!args) {
659
+ continue;
660
+ }
661
+ return {
662
+ nonce: BigInt(args.nonce),
663
+ payload: {
664
+ origin: args.payload.origin,
665
+ assets: args.payload.assets.map((asset) => [
666
+ Number(asset.kind),
667
+ asset.data,
668
+ ]),
669
+ xcm: [Number(args.payload.xcm.kind), args.payload.xcm.data],
670
+ claimer: args.payload.claimer,
671
+ value: BigInt(args.payload.value),
672
+ executionFee: BigInt(args.payload.executionFee),
673
+ relayerFee: BigInt(args.payload.relayerFee),
674
+ },
675
+ blockHash: receipt.blockHash,
676
+ blockNumber: Number(receipt.blockNumber),
677
+ txHash: receipt.transactionHash,
678
+ txIndex: Number(receipt.transactionIndex),
679
+ };
680
+ }
681
+ } catch {}
682
+ }
683
+ return null;
684
+ }
685
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "composite": true,
4
+ "target": "es2021",
5
+ "module": "commonjs",
6
+ "strict": true,
7
+ "resolveJsonModule": true,
8
+ "esModuleInterop": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "outDir": "dist",
11
+ "allowSyntheticDefaultImports": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "baseUrl": ".",
15
+ "rootDir": "src",
16
+ "noEmitOnError": true,
17
+ "skipLibCheck": true,
18
+ "allowJs": true
19
+ },
20
+ "ts-node": {
21
+ "require": ["tsconfig-paths/register"]
22
+ },
23
+ "exclude": ["node_modules", "dist"],
24
+ "include": ["src/**/*.ts"],
25
+ "references": []
26
+ }