@polymarbot/shared 0.5.4 → 0.6.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,73 @@
1
+ // src/utils/wallet.ts
2
+ import { createPublicClient, http, formatUnits, parseAbi } from "viem";
3
+ import { polygon } from "viem/chains";
4
+ var USDC_ADDRESS = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
5
+ var USDC_DECIMALS = 6;
6
+ var USDC_ABI = parseAbi(["function balanceOf(address) view returns (uint256)"]);
7
+ var getPublicClient = /* @__PURE__ */ (() => {
8
+ let client = null;
9
+ let batchClient = null;
10
+ return (options) => {
11
+ const rpcUrl = process.env.POLYGON_RPC || polygon.rpcUrls.default.http[0];
12
+ if (options?.batch) {
13
+ if (!batchClient) {
14
+ batchClient = createPublicClient({
15
+ chain: polygon,
16
+ transport: http(rpcUrl, { batch: { batchSize: 100, wait: 0 } })
17
+ });
18
+ }
19
+ return batchClient;
20
+ }
21
+ if (!client) {
22
+ client = createPublicClient({
23
+ chain: polygon,
24
+ transport: http(rpcUrl)
25
+ });
26
+ }
27
+ return client;
28
+ };
29
+ })();
30
+ function formatBalance(rawBalance, decimals = USDC_DECIMALS) {
31
+ const num = parseFloat(formatUnits(BigInt(rawBalance), decimals));
32
+ return (Math.floor(num * 100) / 100).toFixed(2);
33
+ }
34
+ async function getUSDCBalance(address) {
35
+ const publicClient = getPublicClient();
36
+ return await publicClient.readContract({
37
+ address: USDC_ADDRESS,
38
+ abi: USDC_ABI,
39
+ functionName: "balanceOf",
40
+ args: [address]
41
+ });
42
+ }
43
+ async function getUSDCBalancesBatch(addresses) {
44
+ if (addresses.length === 0) {
45
+ return [];
46
+ }
47
+ const publicClient = getPublicClient();
48
+ return await publicClient.multicall({
49
+ contracts: addresses.map((address) => ({
50
+ address: USDC_ADDRESS,
51
+ abi: USDC_ABI,
52
+ functionName: "balanceOf",
53
+ args: [address]
54
+ })),
55
+ allowFailure: true
56
+ });
57
+ }
58
+ function isAddressEqual(a, b) {
59
+ if (!a) return false;
60
+ if (!b) return false;
61
+ return a.toLowerCase() === b.toLowerCase();
62
+ }
63
+
64
+ export {
65
+ USDC_ADDRESS,
66
+ USDC_DECIMALS,
67
+ USDC_ABI,
68
+ getPublicClient,
69
+ formatBalance,
70
+ getUSDCBalance,
71
+ getUSDCBalancesBatch,
72
+ isAddressEqual
73
+ };
package/index.cjs CHANGED
@@ -7,6 +7,7 @@ module.exports = {
7
7
  ...require('./markets/types.cjs'),
8
8
  ...require('./markets/utils.cjs'),
9
9
  ...require('./relayer-client.cjs'),
10
+ ...require('./safe-executor.cjs'),
10
11
  ...require('./trade-strategy/normalize.cjs'),
11
12
  ...require('./trade-strategy/types.cjs'),
12
13
  ...require('./wallet.cjs')
package/index.d.cts CHANGED
@@ -6,6 +6,7 @@ export * from './load-env.js'
6
6
  export * from './markets/types.js'
7
7
  export * from './markets/utils.js'
8
8
  export * from './relayer-client.js'
9
+ export * from './safe-executor.js'
9
10
  export * from './trade-strategy/normalize.js'
10
11
  export * from './trade-strategy/types.js'
11
12
  export * from './wallet.js'
package/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from './load-env.js'
6
6
  export * from './markets/types.js'
7
7
  export * from './markets/utils.js'
8
8
  export * from './relayer-client.js'
9
+ export * from './safe-executor.js'
9
10
  export * from './trade-strategy/normalize.js'
10
11
  export * from './trade-strategy/types.js'
11
12
  export * from './wallet.js'
package/index.js CHANGED
@@ -6,6 +6,7 @@ export * from './load-env.js'
6
6
  export * from './markets/types.js'
7
7
  export * from './markets/utils.js'
8
8
  export * from './relayer-client.js'
9
+ export * from './safe-executor.js'
9
10
  export * from './trade-strategy/normalize.js'
10
11
  export * from './trade-strategy/types.js'
11
12
  export * from './wallet.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymarbot/shared",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "main": "./index.cjs",
6
6
  "module": "./index.js",
@@ -96,6 +96,16 @@
96
96
  "default": "./relayer-client.cjs"
97
97
  }
98
98
  },
99
+ "./safe-executor": {
100
+ "import": {
101
+ "types": "./safe-executor.d.ts",
102
+ "default": "./safe-executor.js"
103
+ },
104
+ "require": {
105
+ "types": "./safe-executor.d.cts",
106
+ "default": "./safe-executor.cjs"
107
+ }
108
+ },
99
109
  "./trade-strategy/normalize": {
100
110
  "import": {
101
111
  "types": "./trade-strategy/normalize.d.ts",
@@ -134,9 +144,10 @@
134
144
  "**/*.d.cts"
135
145
  ],
136
146
  "dependencies": {
137
- "dotenv": "^17.3.1",
138
147
  "viem": "^2.46.2",
148
+ "dotenv": "^17.3.1",
139
149
  "@polymarket/builder-relayer-client": "^0.0.8",
140
- "@polymarket/builder-signing-sdk": "^0.0.8"
150
+ "@polymarket/builder-signing-sdk": "^0.0.8",
151
+ "p-limit": "^7.3.0"
141
152
  }
142
153
  }
@@ -0,0 +1,191 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/utils/safe-executor.ts
31
+ var safe_executor_exports = {};
32
+ __export(safe_executor_exports, {
33
+ execSafeTransaction: () => execSafeTransaction
34
+ });
35
+ module.exports = __toCommonJS(safe_executor_exports);
36
+ var import_viem2 = require("viem");
37
+ var import_accounts = require("viem/accounts");
38
+ var import_chains2 = require("viem/chains");
39
+ var import_builder_relayer_client = require("@polymarket/builder-relayer-client");
40
+
41
+ // src/utils/wallet.ts
42
+ var import_viem = require("viem");
43
+ var import_chains = require("viem/chains");
44
+ var USDC_ABI = (0, import_viem.parseAbi)(["function balanceOf(address) view returns (uint256)"]);
45
+ var getPublicClient = /* @__PURE__ */ (() => {
46
+ let client = null;
47
+ let batchClient = null;
48
+ return (options) => {
49
+ const rpcUrl = process.env.POLYGON_RPC || import_chains.polygon.rpcUrls.default.http[0];
50
+ if (options?.batch) {
51
+ if (!batchClient) {
52
+ batchClient = (0, import_viem.createPublicClient)({
53
+ chain: import_chains.polygon,
54
+ transport: (0, import_viem.http)(rpcUrl, { batch: { batchSize: 100, wait: 0 } })
55
+ });
56
+ }
57
+ return batchClient;
58
+ }
59
+ if (!client) {
60
+ client = (0, import_viem.createPublicClient)({
61
+ chain: import_chains.polygon,
62
+ transport: (0, import_viem.http)(rpcUrl)
63
+ });
64
+ }
65
+ return client;
66
+ };
67
+ })();
68
+
69
+ // src/utils/safe-executor.ts
70
+ var import_p_limit = __toESM(require("p-limit"), 1);
71
+ var SAFE_MULTISEND = "0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761";
72
+ var SAFE_ABI = (0, import_viem2.parseAbi)([
73
+ "function execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) payable returns (bool success)",
74
+ "function nonce() view returns (uint256)"
75
+ ]);
76
+ var SAFE_TX_TYPES = {
77
+ SafeTx: [
78
+ { name: "to", type: "address" },
79
+ { name: "value", type: "uint256" },
80
+ { name: "data", type: "bytes" },
81
+ { name: "operation", type: "uint8" },
82
+ { name: "safeTxGas", type: "uint256" },
83
+ { name: "baseGas", type: "uint256" },
84
+ { name: "gasPrice", type: "uint256" },
85
+ { name: "gasToken", type: "address" },
86
+ { name: "refundReceiver", type: "address" },
87
+ { name: "nonce", type: "uint256" }
88
+ ]
89
+ };
90
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
91
+ var gasPayerLimit = (0, import_p_limit.default)(1);
92
+ function aggregateTransaction(txns) {
93
+ if (txns.length === 0) {
94
+ throw new Error("No transactions to aggregate");
95
+ }
96
+ if (txns.length === 1) {
97
+ return txns[0];
98
+ }
99
+ return (0, import_builder_relayer_client.createSafeMultisendTransaction)(txns, SAFE_MULTISEND);
100
+ }
101
+ function createSafeTxHash(chainId, safeAddress, tx, nonce) {
102
+ return (0, import_viem2.hashTypedData)({
103
+ domain: {
104
+ chainId,
105
+ verifyingContract: safeAddress
106
+ },
107
+ types: SAFE_TX_TYPES,
108
+ primaryType: "SafeTx",
109
+ message: {
110
+ to: tx.to,
111
+ value: BigInt(tx.value),
112
+ data: tx.data,
113
+ operation: tx.operation,
114
+ safeTxGas: 0n,
115
+ baseGas: 0n,
116
+ gasPrice: 0n,
117
+ gasToken: ZERO_ADDRESS,
118
+ refundReceiver: ZERO_ADDRESS,
119
+ nonce
120
+ }
121
+ });
122
+ }
123
+ async function signSafeTransaction(ownerPrivateKey, structHash) {
124
+ const account = (0, import_accounts.privateKeyToAccount)(ownerPrivateKey);
125
+ const signature = await account.signMessage({
126
+ message: { raw: (0, import_viem2.toBytes)(structHash) }
127
+ });
128
+ const r = signature.slice(0, 66);
129
+ const s = "0x" + signature.slice(66, 130);
130
+ const v = parseInt(signature.slice(130, 132), 16);
131
+ const adjustedV = v + 4;
132
+ return (0, import_viem2.encodePacked)(
133
+ ["bytes32", "bytes32", "uint8"],
134
+ [r, s, adjustedV]
135
+ );
136
+ }
137
+ async function execSafeTransaction(params) {
138
+ const {
139
+ safeAddress,
140
+ ownerPrivateKey,
141
+ gasPayerPrivateKey,
142
+ transactions,
143
+ chainId = import_chains2.polygon.id
144
+ } = params;
145
+ const aggregatedTx = aggregateTransaction(transactions);
146
+ const publicClient = getPublicClient();
147
+ const safeNonce = await publicClient.readContract({
148
+ address: safeAddress,
149
+ abi: SAFE_ABI,
150
+ functionName: "nonce"
151
+ });
152
+ const safeTxHash = createSafeTxHash(chainId, safeAddress, aggregatedTx, safeNonce);
153
+ const signature = await signSafeTransaction(ownerPrivateKey, safeTxHash);
154
+ const txHash = await gasPayerLimit(async () => {
155
+ const rpcUrl = process.env.POLYGON_RPC || import_chains2.polygon.rpcUrls.default.http[0];
156
+ const gasPayerAccount = (0, import_accounts.privateKeyToAccount)(gasPayerPrivateKey);
157
+ const gasPayerWallet = (0, import_viem2.createWalletClient)({
158
+ account: gasPayerAccount,
159
+ chain: import_chains2.polygon,
160
+ transport: (0, import_viem2.http)(rpcUrl)
161
+ });
162
+ const hash = await gasPayerWallet.writeContract({
163
+ address: safeAddress,
164
+ abi: SAFE_ABI,
165
+ functionName: "execTransaction",
166
+ args: [
167
+ aggregatedTx.to,
168
+ BigInt(aggregatedTx.value),
169
+ aggregatedTx.data,
170
+ aggregatedTx.operation,
171
+ 0n,
172
+ // safeTxGas
173
+ 0n,
174
+ // baseGas
175
+ 0n,
176
+ // gasPrice
177
+ ZERO_ADDRESS,
178
+ // gasToken
179
+ ZERO_ADDRESS,
180
+ // refundReceiver
181
+ signature
182
+ ]
183
+ });
184
+ return hash;
185
+ });
186
+ return txHash;
187
+ }
188
+ // Annotate the CommonJS export names for ESM import in node:
189
+ 0 && (module.exports = {
190
+ execSafeTransaction
191
+ });
@@ -0,0 +1,19 @@
1
+ import { Address, Hex, Hash } from 'viem';
2
+ import { SafeTransaction } from '@polymarket/builder-relayer-client';
3
+
4
+ interface ExecSafeTransactionParams {
5
+
6
+ safeAddress: Address;
7
+
8
+ ownerPrivateKey: Hex;
9
+
10
+ gasPayerPrivateKey: Hex;
11
+
12
+ transactions: SafeTransaction[];
13
+
14
+ chainId?: number;
15
+ }
16
+
17
+ declare function execSafeTransaction(params: ExecSafeTransactionParams): Promise<Hash>;
18
+
19
+ export { type ExecSafeTransactionParams, execSafeTransaction };
@@ -0,0 +1,19 @@
1
+ import { Address, Hex, Hash } from 'viem';
2
+ import { SafeTransaction } from '@polymarket/builder-relayer-client';
3
+
4
+ interface ExecSafeTransactionParams {
5
+
6
+ safeAddress: Address;
7
+
8
+ ownerPrivateKey: Hex;
9
+
10
+ gasPayerPrivateKey: Hex;
11
+
12
+ transactions: SafeTransaction[];
13
+
14
+ chainId?: number;
15
+ }
16
+
17
+ declare function execSafeTransaction(params: ExecSafeTransactionParams): Promise<Hash>;
18
+
19
+ export { type ExecSafeTransactionParams, execSafeTransaction };
@@ -0,0 +1,138 @@
1
+ import {
2
+ getPublicClient
3
+ } from "./chunk-LHBGF66E.js";
4
+ import "./chunk-JSBRDJBE.js";
5
+
6
+ // src/utils/safe-executor.ts
7
+ import {
8
+ createWalletClient,
9
+ encodePacked,
10
+ hashTypedData,
11
+ http,
12
+ parseAbi,
13
+ toBytes
14
+ } from "viem";
15
+ import { privateKeyToAccount } from "viem/accounts";
16
+ import { polygon } from "viem/chains";
17
+ import { createSafeMultisendTransaction } from "@polymarket/builder-relayer-client";
18
+ import pLimit from "p-limit";
19
+ var SAFE_MULTISEND = "0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761";
20
+ var SAFE_ABI = parseAbi([
21
+ "function execTransaction(address to, uint256 value, bytes data, uint8 operation, uint256 safeTxGas, uint256 baseGas, uint256 gasPrice, address gasToken, address refundReceiver, bytes signatures) payable returns (bool success)",
22
+ "function nonce() view returns (uint256)"
23
+ ]);
24
+ var SAFE_TX_TYPES = {
25
+ SafeTx: [
26
+ { name: "to", type: "address" },
27
+ { name: "value", type: "uint256" },
28
+ { name: "data", type: "bytes" },
29
+ { name: "operation", type: "uint8" },
30
+ { name: "safeTxGas", type: "uint256" },
31
+ { name: "baseGas", type: "uint256" },
32
+ { name: "gasPrice", type: "uint256" },
33
+ { name: "gasToken", type: "address" },
34
+ { name: "refundReceiver", type: "address" },
35
+ { name: "nonce", type: "uint256" }
36
+ ]
37
+ };
38
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
39
+ var gasPayerLimit = pLimit(1);
40
+ function aggregateTransaction(txns) {
41
+ if (txns.length === 0) {
42
+ throw new Error("No transactions to aggregate");
43
+ }
44
+ if (txns.length === 1) {
45
+ return txns[0];
46
+ }
47
+ return createSafeMultisendTransaction(txns, SAFE_MULTISEND);
48
+ }
49
+ function createSafeTxHash(chainId, safeAddress, tx, nonce) {
50
+ return hashTypedData({
51
+ domain: {
52
+ chainId,
53
+ verifyingContract: safeAddress
54
+ },
55
+ types: SAFE_TX_TYPES,
56
+ primaryType: "SafeTx",
57
+ message: {
58
+ to: tx.to,
59
+ value: BigInt(tx.value),
60
+ data: tx.data,
61
+ operation: tx.operation,
62
+ safeTxGas: 0n,
63
+ baseGas: 0n,
64
+ gasPrice: 0n,
65
+ gasToken: ZERO_ADDRESS,
66
+ refundReceiver: ZERO_ADDRESS,
67
+ nonce
68
+ }
69
+ });
70
+ }
71
+ async function signSafeTransaction(ownerPrivateKey, structHash) {
72
+ const account = privateKeyToAccount(ownerPrivateKey);
73
+ const signature = await account.signMessage({
74
+ message: { raw: toBytes(structHash) }
75
+ });
76
+ const r = signature.slice(0, 66);
77
+ const s = "0x" + signature.slice(66, 130);
78
+ const v = parseInt(signature.slice(130, 132), 16);
79
+ const adjustedV = v + 4;
80
+ return encodePacked(
81
+ ["bytes32", "bytes32", "uint8"],
82
+ [r, s, adjustedV]
83
+ );
84
+ }
85
+ async function execSafeTransaction(params) {
86
+ const {
87
+ safeAddress,
88
+ ownerPrivateKey,
89
+ gasPayerPrivateKey,
90
+ transactions,
91
+ chainId = polygon.id
92
+ } = params;
93
+ const aggregatedTx = aggregateTransaction(transactions);
94
+ const publicClient = getPublicClient();
95
+ const safeNonce = await publicClient.readContract({
96
+ address: safeAddress,
97
+ abi: SAFE_ABI,
98
+ functionName: "nonce"
99
+ });
100
+ const safeTxHash = createSafeTxHash(chainId, safeAddress, aggregatedTx, safeNonce);
101
+ const signature = await signSafeTransaction(ownerPrivateKey, safeTxHash);
102
+ const txHash = await gasPayerLimit(async () => {
103
+ const rpcUrl = process.env.POLYGON_RPC || polygon.rpcUrls.default.http[0];
104
+ const gasPayerAccount = privateKeyToAccount(gasPayerPrivateKey);
105
+ const gasPayerWallet = createWalletClient({
106
+ account: gasPayerAccount,
107
+ chain: polygon,
108
+ transport: http(rpcUrl)
109
+ });
110
+ const hash = await gasPayerWallet.writeContract({
111
+ address: safeAddress,
112
+ abi: SAFE_ABI,
113
+ functionName: "execTransaction",
114
+ args: [
115
+ aggregatedTx.to,
116
+ BigInt(aggregatedTx.value),
117
+ aggregatedTx.data,
118
+ aggregatedTx.operation,
119
+ 0n,
120
+ // safeTxGas
121
+ 0n,
122
+ // baseGas
123
+ 0n,
124
+ // gasPrice
125
+ ZERO_ADDRESS,
126
+ // gasToken
127
+ ZERO_ADDRESS,
128
+ // refundReceiver
129
+ signature
130
+ ]
131
+ });
132
+ return hash;
133
+ });
134
+ return txHash;
135
+ }
136
+ export {
137
+ execSafeTransaction
138
+ };
@@ -80,6 +80,7 @@ interface TokenTradeStepOrder {
80
80
  size: number;
81
81
  status: string;
82
82
  updatedAt: number;
83
+ expiresAt?: number;
83
84
  keep?: boolean;
84
85
  }
85
86
 
@@ -80,6 +80,7 @@ interface TokenTradeStepOrder {
80
80
  size: number;
81
81
  status: string;
82
82
  updatedAt: number;
83
+ expiresAt?: number;
83
84
  keep?: boolean;
84
85
  }
85
86
 
package/wallet.js CHANGED
@@ -1,67 +1,14 @@
1
+ import {
2
+ USDC_ABI,
3
+ USDC_ADDRESS,
4
+ USDC_DECIMALS,
5
+ formatBalance,
6
+ getPublicClient,
7
+ getUSDCBalance,
8
+ getUSDCBalancesBatch,
9
+ isAddressEqual
10
+ } from "./chunk-LHBGF66E.js";
1
11
  import "./chunk-JSBRDJBE.js";
2
-
3
- // src/utils/wallet.ts
4
- import { createPublicClient, http, formatUnits, parseAbi } from "viem";
5
- import { polygon } from "viem/chains";
6
- var USDC_ADDRESS = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
7
- var USDC_DECIMALS = 6;
8
- var USDC_ABI = parseAbi(["function balanceOf(address) view returns (uint256)"]);
9
- var getPublicClient = /* @__PURE__ */ (() => {
10
- let client = null;
11
- let batchClient = null;
12
- return (options) => {
13
- const rpcUrl = process.env.POLYGON_RPC || polygon.rpcUrls.default.http[0];
14
- if (options?.batch) {
15
- if (!batchClient) {
16
- batchClient = createPublicClient({
17
- chain: polygon,
18
- transport: http(rpcUrl, { batch: { batchSize: 100, wait: 0 } })
19
- });
20
- }
21
- return batchClient;
22
- }
23
- if (!client) {
24
- client = createPublicClient({
25
- chain: polygon,
26
- transport: http(rpcUrl)
27
- });
28
- }
29
- return client;
30
- };
31
- })();
32
- function formatBalance(rawBalance, decimals = USDC_DECIMALS) {
33
- const num = parseFloat(formatUnits(BigInt(rawBalance), decimals));
34
- return (Math.floor(num * 100) / 100).toFixed(2);
35
- }
36
- async function getUSDCBalance(address) {
37
- const publicClient = getPublicClient();
38
- return await publicClient.readContract({
39
- address: USDC_ADDRESS,
40
- abi: USDC_ABI,
41
- functionName: "balanceOf",
42
- args: [address]
43
- });
44
- }
45
- async function getUSDCBalancesBatch(addresses) {
46
- if (addresses.length === 0) {
47
- return [];
48
- }
49
- const publicClient = getPublicClient();
50
- return await publicClient.multicall({
51
- contracts: addresses.map((address) => ({
52
- address: USDC_ADDRESS,
53
- abi: USDC_ABI,
54
- functionName: "balanceOf",
55
- args: [address]
56
- })),
57
- allowFailure: true
58
- });
59
- }
60
- function isAddressEqual(a, b) {
61
- if (!a) return false;
62
- if (!b) return false;
63
- return a.toLowerCase() === b.toLowerCase();
64
- }
65
12
  export {
66
13
  USDC_ABI,
67
14
  USDC_ADDRESS,