@ab-org/predicate-market-sdk 2.0.0 → 2.0.1-beta.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.
- package/README.md +39 -6
- package/dist/account-F5Z2SMJE.js +213 -0
- package/dist/api-DyQAYQ0i.d.ts +156 -0
- package/dist/auth.d.ts +8 -0
- package/dist/auth.js +1 -0
- package/dist/autoReconnect-6YV7YSSL.js +4 -0
- package/dist/chunk-26RFAFJG.js +31 -0
- package/dist/chunk-66CHMJG7.js +527 -0
- package/dist/chunk-6YQEHB6P.js +14 -0
- package/dist/chunk-C5BV2OG7.js +6 -0
- package/dist/chunk-F2UPP3YC.js +88 -0
- package/dist/chunk-F3HQRJID.js +149 -0
- package/dist/chunk-SHLNBZBY.js +72 -0
- package/dist/chunk-SZYGIQT3.js +3192 -0
- package/dist/chunk-TPMI3XWV.js +114 -0
- package/dist/chunk-UAXKA6QC.js +17 -0
- package/dist/chunk-WHTI52FI.js +10 -0
- package/dist/chunk-XB2DFS2W.js +50 -0
- package/dist/chunk-YX56ZGDB.js +274 -0
- package/dist/core.d.ts +63 -0
- package/dist/core.js +6 -0
- package/dist/dist-Q2PDXT2F.js +81 -0
- package/dist/index.d.ts +12 -706
- package/dist/index.js +13 -43009
- package/dist/merchant.d.ts +187 -0
- package/dist/merchant.js +7 -0
- package/dist/react.d.ts +197 -0
- package/dist/react.js +7 -0
- package/dist/signInTypes-DESvmgWG.d.ts +41 -0
- package/dist/types-BFidNjd9.d.ts +64 -0
- package/package.json +23 -11
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
import { getChainInfo, getFundingTokenAddress, DEFAULT_FUNDING_CHAIN_ID } from './chunk-F2UPP3YC.js';
|
|
2
|
+
import { getChains, createOrder } from './chunk-TPMI3XWV.js';
|
|
3
|
+
import { tryAutoReconnect } from './chunk-26RFAFJG.js';
|
|
4
|
+
import { getEnv } from './chunk-SHLNBZBY.js';
|
|
5
|
+
import { sessionStore, createSessionCapabilityPolicy } from '@ab-org/sdk-core';
|
|
6
|
+
import { toHex, fromHex, parseGwei, formatUnits } from 'viem';
|
|
7
|
+
|
|
8
|
+
function requireSession() {
|
|
9
|
+
const session = sessionStore.getState().session;
|
|
10
|
+
if (!session) throw new Error("Login required");
|
|
11
|
+
return session;
|
|
12
|
+
}
|
|
13
|
+
var createDepositController = (custody, marketData) => {
|
|
14
|
+
let status = { phase: "idle" };
|
|
15
|
+
const notify = (next, cb) => {
|
|
16
|
+
status = next;
|
|
17
|
+
cb?.(status);
|
|
18
|
+
};
|
|
19
|
+
const open = async (config) => {
|
|
20
|
+
const session = requireSession();
|
|
21
|
+
const chain = config?.preferredChain ?? session.chainContext?.settlementChain ?? session.chain ?? "AB_CORE";
|
|
22
|
+
const token = config?.preferredToken || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
|
|
23
|
+
try {
|
|
24
|
+
const { address } = await marketData.getDepositAddress(token, chain);
|
|
25
|
+
const depositId = `${chain}:${token}:${Date.now()}`;
|
|
26
|
+
notify({ phase: "address-issued", depositId, address }, config?.onStatusChange);
|
|
27
|
+
notify({ phase: "confirming", depositId }, config?.onStatusChange);
|
|
28
|
+
const { status: finalStatus, txHash } = await custody.getDepositStatus(depositId);
|
|
29
|
+
notify(
|
|
30
|
+
finalStatus === "SETTLED" ? { phase: "settled", depositId, txHash } : { phase: "failed", reason: finalStatus },
|
|
31
|
+
config?.onStatusChange
|
|
32
|
+
);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
notify({ phase: "failed", reason: error.message }, config?.onStatusChange);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
get status() {
|
|
39
|
+
return status;
|
|
40
|
+
},
|
|
41
|
+
open,
|
|
42
|
+
fetchTokens() {
|
|
43
|
+
requireSession();
|
|
44
|
+
return marketData.getSupportedTokens("deposit");
|
|
45
|
+
},
|
|
46
|
+
fetchChains(token) {
|
|
47
|
+
requireSession();
|
|
48
|
+
return marketData.getSupportedChains(token, "deposit");
|
|
49
|
+
},
|
|
50
|
+
fetchQuote(token, chain, amount) {
|
|
51
|
+
requireSession();
|
|
52
|
+
return marketData.getQuote({ token, chain, amount, direction: "deposit" });
|
|
53
|
+
},
|
|
54
|
+
fetchDepositAddress(token, chain) {
|
|
55
|
+
requireSession();
|
|
56
|
+
return marketData.getDepositAddress(token, chain);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
function requireSession2() {
|
|
61
|
+
const session = sessionStore.getState().session;
|
|
62
|
+
if (!session) throw new Error("Login required");
|
|
63
|
+
return session;
|
|
64
|
+
}
|
|
65
|
+
var createWithdrawController = (custody, marketData) => {
|
|
66
|
+
let status = { phase: "idle" };
|
|
67
|
+
const update = (next, cb) => {
|
|
68
|
+
status = next;
|
|
69
|
+
cb?.(status);
|
|
70
|
+
};
|
|
71
|
+
const open = async (config) => {
|
|
72
|
+
const session = requireSession2();
|
|
73
|
+
const token = config?.defaultToken || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
|
|
74
|
+
const chain = config?.defaultChain ?? session.chainContext?.settlementChain ?? session.chain ?? "AB_CORE";
|
|
75
|
+
const targetAddress = config?.targetAddress;
|
|
76
|
+
if (!targetAddress) throw new Error("targetAddress required for withdraw");
|
|
77
|
+
try {
|
|
78
|
+
const { requestId } = await custody.requestWithdraw({
|
|
79
|
+
amount: config?.defaultAmount ?? "0",
|
|
80
|
+
token,
|
|
81
|
+
chain,
|
|
82
|
+
targetAddress
|
|
83
|
+
});
|
|
84
|
+
update({ phase: "requested", requestId }, config?.onStatusChange);
|
|
85
|
+
update({ phase: "processing", requestId }, config?.onStatusChange);
|
|
86
|
+
const { status: finalStatus, txHash } = await custody.getWithdrawStatus(requestId);
|
|
87
|
+
update(
|
|
88
|
+
finalStatus === "SETTLED" ? { phase: "settled", requestId, txHash } : { phase: "failed", reason: finalStatus },
|
|
89
|
+
config?.onStatusChange
|
|
90
|
+
);
|
|
91
|
+
} catch (error) {
|
|
92
|
+
update({ phase: "failed", reason: error.message }, config?.onStatusChange);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
get status() {
|
|
97
|
+
return status;
|
|
98
|
+
},
|
|
99
|
+
open,
|
|
100
|
+
fetchTokens() {
|
|
101
|
+
requireSession2();
|
|
102
|
+
return marketData.getSupportedTokens("withdraw");
|
|
103
|
+
},
|
|
104
|
+
fetchChains(token) {
|
|
105
|
+
requireSession2();
|
|
106
|
+
return marketData.getSupportedChains(token, "withdraw");
|
|
107
|
+
},
|
|
108
|
+
fetchQuote(token, chain, amount) {
|
|
109
|
+
requireSession2();
|
|
110
|
+
return marketData.getQuote({ token, chain, amount, direction: "withdraw" });
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
var cachedChains = null;
|
|
115
|
+
async function fetchChainsFromApi() {
|
|
116
|
+
if (cachedChains) return cachedChains;
|
|
117
|
+
try {
|
|
118
|
+
const { chains } = await getChains();
|
|
119
|
+
if (chains.length > 0) {
|
|
120
|
+
cachedChains = chains;
|
|
121
|
+
return chains;
|
|
122
|
+
}
|
|
123
|
+
return [];
|
|
124
|
+
} catch {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function chainToChainInfo(chain) {
|
|
129
|
+
return {
|
|
130
|
+
id: chain.chain_id,
|
|
131
|
+
name: chain.network
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function findTokenInChains(chains, chainId, tokenSymbol) {
|
|
135
|
+
const chain = chains.find((c) => c.chain_id === chainId);
|
|
136
|
+
return chain?.tokens.find((t) => t.symbol === tokenSymbol);
|
|
137
|
+
}
|
|
138
|
+
function formatMinimumDepositDisplay(token, tokenSymbol) {
|
|
139
|
+
const raw = token.minimum_deposit?.trim();
|
|
140
|
+
if (raw == null || raw === "") return void 0;
|
|
141
|
+
try {
|
|
142
|
+
return `${formatUnits(BigInt(raw), token.decimals)} ${tokenSymbol}`;
|
|
143
|
+
} catch {
|
|
144
|
+
return `${raw} ${tokenSymbol}`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function deriveTokensFromChains(chains) {
|
|
148
|
+
const bySymbol = /* @__PURE__ */ new Map();
|
|
149
|
+
for (const chain of chains) {
|
|
150
|
+
for (const t of chain.tokens) {
|
|
151
|
+
if (!bySymbol.has(t.symbol)) {
|
|
152
|
+
bySymbol.set(t.symbol, {
|
|
153
|
+
symbol: t.symbol,
|
|
154
|
+
name: t.symbol,
|
|
155
|
+
decimals: t.decimals
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return Array.from(bySymbol.values());
|
|
161
|
+
}
|
|
162
|
+
function computeDefaultQuote(request) {
|
|
163
|
+
const isStable = ["USDT", "USDC", "USD1"].includes(request.token);
|
|
164
|
+
const slippage = isStable ? "0.3" : "1.0";
|
|
165
|
+
const feeRate = request.direction === "withdraw" ? 1e-3 : 0;
|
|
166
|
+
const amount = Number(request.amount) || 0;
|
|
167
|
+
const fee = (amount * feeRate).toFixed(2);
|
|
168
|
+
const estimatedAmount = (amount - Number(fee)).toFixed(6);
|
|
169
|
+
return {
|
|
170
|
+
quoteId: `quote-${Date.now()}`,
|
|
171
|
+
estimatedAmount: amount > 0 ? estimatedAmount : "0",
|
|
172
|
+
slippage,
|
|
173
|
+
fee,
|
|
174
|
+
feeToken: request.token,
|
|
175
|
+
exchangeRate: "1.0",
|
|
176
|
+
expiresAt: Date.now() + 3e4
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function createMarketDataProvider() {
|
|
180
|
+
return {
|
|
181
|
+
async getSupportedTokens(_direction) {
|
|
182
|
+
const chains = await fetchChainsFromApi();
|
|
183
|
+
const tokens = deriveTokensFromChains(chains);
|
|
184
|
+
return tokens.length > 0 ? tokens : [];
|
|
185
|
+
},
|
|
186
|
+
async getSupportedChains(token, _direction) {
|
|
187
|
+
const chains = await fetchChainsFromApi();
|
|
188
|
+
const forToken = chains.filter((c) => c.tokens.some((t) => t.symbol === token));
|
|
189
|
+
const list = forToken.length > 0 ? forToken : chains;
|
|
190
|
+
return list.map(chainToChainInfo);
|
|
191
|
+
},
|
|
192
|
+
async getQuote(request) {
|
|
193
|
+
return computeDefaultQuote(request);
|
|
194
|
+
},
|
|
195
|
+
async getDepositAddress(token, chain) {
|
|
196
|
+
const session = sessionStore.getState().session;
|
|
197
|
+
const chains = await fetchChainsFromApi();
|
|
198
|
+
const meta = findTokenInChains(chains, chain, token);
|
|
199
|
+
const minimumDeposit = meta != null ? formatMinimumDepositDisplay(meta, token) : void 0;
|
|
200
|
+
return {
|
|
201
|
+
address: session?.address ?? "",
|
|
202
|
+
minimumDeposit
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/modules/balanceQuery.ts
|
|
209
|
+
var ERC20_BALANCE_OF_SELECTOR = "0x70a08231";
|
|
210
|
+
function padAddress(address) {
|
|
211
|
+
return address.toLowerCase().replace("0x", "").padStart(64, "0");
|
|
212
|
+
}
|
|
213
|
+
function formatUnits2(value, decimals) {
|
|
214
|
+
const divisor = 10n ** BigInt(decimals);
|
|
215
|
+
const intPart = value / divisor;
|
|
216
|
+
const fracPart = value % divisor;
|
|
217
|
+
if (fracPart === 0n) return intPart.toString();
|
|
218
|
+
const fracStr = fracPart.toString().padStart(decimals, "0").replace(/0+$/, "");
|
|
219
|
+
return `${intPart}.${fracStr}`;
|
|
220
|
+
}
|
|
221
|
+
function formatBalanceDisplay(value, decimals) {
|
|
222
|
+
const full = formatUnits2(value, decimals);
|
|
223
|
+
const n = Number(full);
|
|
224
|
+
return Number.isNaN(n) ? full : n.toFixed(2);
|
|
225
|
+
}
|
|
226
|
+
async function fetchErc20Balance(rpcUrl, tokenAddress, walletAddress) {
|
|
227
|
+
const data = `${ERC20_BALANCE_OF_SELECTOR}${padAddress(walletAddress)}`;
|
|
228
|
+
const response = await fetch(rpcUrl, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: { "Content-Type": "application/json" },
|
|
231
|
+
body: JSON.stringify({
|
|
232
|
+
jsonrpc: "2.0",
|
|
233
|
+
id: 1,
|
|
234
|
+
method: "eth_call",
|
|
235
|
+
params: [{ to: tokenAddress, data }, "latest"]
|
|
236
|
+
})
|
|
237
|
+
});
|
|
238
|
+
const json = await response.json();
|
|
239
|
+
if (json.error) throw new Error(json.error.message ?? "RPC error");
|
|
240
|
+
return BigInt(json.result ?? "0x0");
|
|
241
|
+
}
|
|
242
|
+
async function fetchFundingTokenBalance(walletAddress, options) {
|
|
243
|
+
const chain = getChainInfo(options?.chainId);
|
|
244
|
+
const rpcUrl = options?.rpcUrl ?? chain.rpcUrls[0];
|
|
245
|
+
const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
|
|
246
|
+
const decimals = options?.decimals ?? chain.nativeCurrencyDecimals;
|
|
247
|
+
const FUNDING_TOKEN_SYMBOL = getEnv("FUNDING_TOKEN_SYMBOL");
|
|
248
|
+
const displaySymbol = options?.displaySymbol ?? (FUNDING_TOKEN_SYMBOL || "Funding");
|
|
249
|
+
const raw = await fetchErc20Balance(rpcUrl, tokenAddress, walletAddress);
|
|
250
|
+
return {
|
|
251
|
+
raw,
|
|
252
|
+
formatted: formatBalanceDisplay(raw, decimals),
|
|
253
|
+
symbol: displaySymbol
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
var MAX_WITHDRAW_GAS_LIMIT = 500000n;
|
|
257
|
+
var ERC20_TRANSFER_SELECTOR = "0xa9059cbb";
|
|
258
|
+
function padHex256(value) {
|
|
259
|
+
return value.toString(16).padStart(64, "0");
|
|
260
|
+
}
|
|
261
|
+
function padAddress2(address) {
|
|
262
|
+
return address.toLowerCase().replace("0x", "").padStart(64, "0");
|
|
263
|
+
}
|
|
264
|
+
function parseUnits(value, decimals) {
|
|
265
|
+
if (!value || value === "0") return 0n;
|
|
266
|
+
const [intPart = "0", fracPart = ""] = value.split(".");
|
|
267
|
+
const padded = fracPart.padEnd(decimals, "0").slice(0, decimals);
|
|
268
|
+
return BigInt(intPart) * 10n ** BigInt(decimals) + BigInt(padded);
|
|
269
|
+
}
|
|
270
|
+
function encodeTransferData(to, amountWei) {
|
|
271
|
+
return `${ERC20_TRANSFER_SELECTOR}${padAddress2(to)}${padHex256(amountWei)}`;
|
|
272
|
+
}
|
|
273
|
+
function isUnsupportedMethodError(error) {
|
|
274
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
275
|
+
return /unsupported rpc method|unsupported method|method not found|does not support/i.test(
|
|
276
|
+
message
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
function toHexQuantity(value) {
|
|
280
|
+
if (typeof value === "string") {
|
|
281
|
+
if (/^0x[0-9a-fA-F]+$/.test(value)) {
|
|
282
|
+
return value;
|
|
283
|
+
}
|
|
284
|
+
if (/^\d+$/.test(value)) {
|
|
285
|
+
return toHex(BigInt(value));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
if (typeof value === "number") {
|
|
289
|
+
return toHex(BigInt(value));
|
|
290
|
+
}
|
|
291
|
+
if (typeof value === "bigint") {
|
|
292
|
+
return toHex(value);
|
|
293
|
+
}
|
|
294
|
+
throw new Error(`Invalid EVM quantity: ${String(value)}`);
|
|
295
|
+
}
|
|
296
|
+
async function callRpc(rpcUrl, method, params) {
|
|
297
|
+
const response = await fetch(rpcUrl, {
|
|
298
|
+
method: "POST",
|
|
299
|
+
headers: { "Content-Type": "application/json" },
|
|
300
|
+
body: JSON.stringify({
|
|
301
|
+
jsonrpc: "2.0",
|
|
302
|
+
id: Date.now(),
|
|
303
|
+
method,
|
|
304
|
+
params
|
|
305
|
+
})
|
|
306
|
+
});
|
|
307
|
+
const json = await response.json();
|
|
308
|
+
if (!response.ok || json.error) {
|
|
309
|
+
throw new Error(json.error?.message ?? `${method} failed`);
|
|
310
|
+
}
|
|
311
|
+
return json.result;
|
|
312
|
+
}
|
|
313
|
+
async function requestHexQuantity(provider, rpcUrl, method, params) {
|
|
314
|
+
try {
|
|
315
|
+
const result = await provider.request({ method, params });
|
|
316
|
+
return toHexQuantity(result);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (!isUnsupportedMethodError(error)) {
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
return toHexQuantity(await callRpc(rpcUrl, method, params));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
async function ensureFundingEvmChain(provider, chainId) {
|
|
325
|
+
const hex = `0x${chainId.toString(16)}`;
|
|
326
|
+
try {
|
|
327
|
+
await provider.request({ method: "wallet_switchEthereumChain", params: [{ chainId: hex }] });
|
|
328
|
+
} catch {
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function getDstTokenAddress(chains, chainId, tokenSymbol) {
|
|
332
|
+
const chain = chains.find((c) => c.chain_id === chainId);
|
|
333
|
+
return chain?.tokens.find((t) => t.symbol === tokenSymbol)?.address;
|
|
334
|
+
}
|
|
335
|
+
function createFundingWithdrawExecutor(options) {
|
|
336
|
+
const fundingChain = getChainInfo(options?.chainId);
|
|
337
|
+
const chainIdNum = Number(fundingChain.chainId);
|
|
338
|
+
const rpcUrl = options?.rpcUrl ?? fundingChain.rpcUrls[0];
|
|
339
|
+
const tokenAddress = options?.tokenAddress ?? getFundingTokenAddress(options?.chainId);
|
|
340
|
+
const decimals = options?.decimals ?? fundingChain.nativeCurrencyDecimals;
|
|
341
|
+
const maxAmountWei = options?.maxAmountWei;
|
|
342
|
+
const fundingLegTokenSymbol = options?.fundingLegTokenSymbol || getEnv("FUNDING_TOKEN_SYMBOL") || "USDT";
|
|
343
|
+
return async (request) => {
|
|
344
|
+
const amountWei = parseUnits(request.amount, decimals);
|
|
345
|
+
const amountWeiStr = amountWei.toString();
|
|
346
|
+
if (maxAmountWei != null && amountWei > BigInt(maxAmountWei)) {
|
|
347
|
+
throw new Error("Withdraw amount exceeds the single-transaction limit");
|
|
348
|
+
}
|
|
349
|
+
let session = sessionStore.getState().session;
|
|
350
|
+
if (!session) throw new Error("Login required");
|
|
351
|
+
let { provider } = session;
|
|
352
|
+
try {
|
|
353
|
+
await provider.request({ method: "eth_chainId", params: [] });
|
|
354
|
+
} catch (err) {
|
|
355
|
+
const msg = err.message ?? "";
|
|
356
|
+
if (msg.includes("restored from cache") || msg.includes("Reconnect your wallet")) {
|
|
357
|
+
const reconnected = await tryAutoReconnect();
|
|
358
|
+
if (reconnected) {
|
|
359
|
+
session = reconnected;
|
|
360
|
+
provider = reconnected.provider;
|
|
361
|
+
} else {
|
|
362
|
+
sessionStore.clearSession();
|
|
363
|
+
throw new Error("Session expired. Please sign in again.");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const chainsRes = await getChains();
|
|
368
|
+
const chains = chainsRes?.chains ?? [];
|
|
369
|
+
const dstTokenAddress = getDstTokenAddress(chains, request.chain, request.token);
|
|
370
|
+
if (!dstTokenAddress) {
|
|
371
|
+
throw new Error(`Unsupported token ${request.token} on chain ${request.chain}`);
|
|
372
|
+
}
|
|
373
|
+
const sourceTokenSymbol = fundingLegTokenSymbol;
|
|
374
|
+
const orderRes = await createOrder({
|
|
375
|
+
intent_id: `withdraw-${Date.now()}`,
|
|
376
|
+
order_type: "NATIVE_SWAP",
|
|
377
|
+
order_payload: {
|
|
378
|
+
chain_id: fundingChain.chainId,
|
|
379
|
+
token_address: tokenAddress,
|
|
380
|
+
token_amount: amountWeiStr,
|
|
381
|
+
dst_chain_id: request.chain,
|
|
382
|
+
dst_token_address: dstTokenAddress,
|
|
383
|
+
recipient: request.toAddress
|
|
384
|
+
},
|
|
385
|
+
payment_pairs: [
|
|
386
|
+
{
|
|
387
|
+
token_symbol: sourceTokenSymbol,
|
|
388
|
+
token_amount: amountWeiStr,
|
|
389
|
+
token_address: tokenAddress,
|
|
390
|
+
user_address: session.address,
|
|
391
|
+
chain_id: fundingChain.chainId
|
|
392
|
+
}
|
|
393
|
+
]
|
|
394
|
+
});
|
|
395
|
+
const oneTimeAddress = orderRes.payment_sessions?.[0]?.one_time_wallet_address;
|
|
396
|
+
if (!oneTimeAddress) {
|
|
397
|
+
throw new Error("Order created but no one-time wallet address returned");
|
|
398
|
+
}
|
|
399
|
+
await ensureFundingEvmChain(provider, chainIdNum);
|
|
400
|
+
const data = encodeTransferData(oneTimeAddress, amountWei);
|
|
401
|
+
const nonce = await requestHexQuantity(
|
|
402
|
+
provider,
|
|
403
|
+
rpcUrl,
|
|
404
|
+
"eth_getTransactionCount",
|
|
405
|
+
[session.address, "latest"]
|
|
406
|
+
);
|
|
407
|
+
const tx = {
|
|
408
|
+
from: session.address,
|
|
409
|
+
to: tokenAddress,
|
|
410
|
+
value: "0x0",
|
|
411
|
+
nonce,
|
|
412
|
+
data,
|
|
413
|
+
chainId: toHex(chainIdNum)
|
|
414
|
+
};
|
|
415
|
+
const estimatedGasHex = await requestHexQuantity(
|
|
416
|
+
provider,
|
|
417
|
+
rpcUrl,
|
|
418
|
+
"eth_estimateGas",
|
|
419
|
+
[tx]
|
|
420
|
+
);
|
|
421
|
+
const estimatedGas = fromHex(estimatedGasHex, "bigint");
|
|
422
|
+
const gas = toHex(
|
|
423
|
+
estimatedGas > MAX_WITHDRAW_GAS_LIMIT ? MAX_WITHDRAW_GAS_LIMIT : estimatedGas
|
|
424
|
+
);
|
|
425
|
+
const transaction = {
|
|
426
|
+
...tx,
|
|
427
|
+
gas,
|
|
428
|
+
maxFeePerGas: toHex(parseGwei("5")),
|
|
429
|
+
maxPriorityFeePerGas: toHex(parseGwei("1"))
|
|
430
|
+
};
|
|
431
|
+
let txHash;
|
|
432
|
+
try {
|
|
433
|
+
txHash = await provider.request({
|
|
434
|
+
method: "eth_sendTransaction",
|
|
435
|
+
params: [transaction]
|
|
436
|
+
});
|
|
437
|
+
} catch (error) {
|
|
438
|
+
if (!isUnsupportedMethodError(error)) {
|
|
439
|
+
throw error;
|
|
440
|
+
}
|
|
441
|
+
const signedTx = await provider.request({
|
|
442
|
+
method: "eth_signTransaction",
|
|
443
|
+
params: [transaction]
|
|
444
|
+
});
|
|
445
|
+
txHash = await callRpc(rpcUrl, "eth_sendRawTransaction", [signedTx]);
|
|
446
|
+
}
|
|
447
|
+
return { txHash, orderId: orderRes.order_id, fundingChainId: fundingChain.chainId };
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// src/modules/withdrawDirect.ts
|
|
452
|
+
function isUsdtWithdrawDirect(chainId, tokenAddress, chains) {
|
|
453
|
+
if (chainId !== String(DEFAULT_FUNDING_CHAIN_ID)) return false;
|
|
454
|
+
const addr = tokenAddress.trim();
|
|
455
|
+
if (!addr) return false;
|
|
456
|
+
const chain = chains.find((c) => c.chain_id === chainId);
|
|
457
|
+
const token = chain?.tokens.find((t) => t.address.toLowerCase() === addr.toLowerCase());
|
|
458
|
+
return token?.is_usd_stable === true;
|
|
459
|
+
}
|
|
460
|
+
function findTokenDataFromChains(chains, chainId, opts) {
|
|
461
|
+
const chain = chains.find((c) => c.chain_id === chainId);
|
|
462
|
+
if (!chain?.tokens.length) return void 0;
|
|
463
|
+
const sym = opts.symbol.trim();
|
|
464
|
+
const addr = opts.tokenAddress?.trim().toLowerCase();
|
|
465
|
+
return chain.tokens.find((t) => {
|
|
466
|
+
if (addr && t.address.toLowerCase() === addr) return true;
|
|
467
|
+
if (sym.length > 0 && t.symbol === sym) return true;
|
|
468
|
+
return false;
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
var createPolicy = (overrides, options) => createSessionCapabilityPolicy({
|
|
472
|
+
appId: options?.appId,
|
|
473
|
+
origin: options?.origin,
|
|
474
|
+
expiresAt: options?.expiresAt,
|
|
475
|
+
...overrides
|
|
476
|
+
});
|
|
477
|
+
var withActionMetadata = (action, policy) => ({
|
|
478
|
+
...policy,
|
|
479
|
+
metadata: {
|
|
480
|
+
...policy.metadata ?? {},
|
|
481
|
+
action
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
var createPredicateMarketPolicyAdapter = (options) => ({
|
|
485
|
+
deposit(token, chain, maxAmount) {
|
|
486
|
+
return withActionMetadata(
|
|
487
|
+
"deposit",
|
|
488
|
+
createPolicy(
|
|
489
|
+
{
|
|
490
|
+
methods: ["eth_sendTransaction"],
|
|
491
|
+
chains: [chain],
|
|
492
|
+
tokens: [token],
|
|
493
|
+
maxAmount
|
|
494
|
+
},
|
|
495
|
+
options
|
|
496
|
+
)
|
|
497
|
+
);
|
|
498
|
+
},
|
|
499
|
+
withdraw(token, chain, maxAmount) {
|
|
500
|
+
return withActionMetadata(
|
|
501
|
+
"withdraw",
|
|
502
|
+
createPolicy(
|
|
503
|
+
{
|
|
504
|
+
methods: ["eth_sendTransaction"],
|
|
505
|
+
chains: [chain],
|
|
506
|
+
tokens: [token],
|
|
507
|
+
maxAmount
|
|
508
|
+
},
|
|
509
|
+
options
|
|
510
|
+
)
|
|
511
|
+
);
|
|
512
|
+
},
|
|
513
|
+
trade(chain, capabilities = ["eth_sendTransaction"]) {
|
|
514
|
+
return withActionMetadata(
|
|
515
|
+
"trade",
|
|
516
|
+
createPolicy(
|
|
517
|
+
{
|
|
518
|
+
methods: capabilities,
|
|
519
|
+
chains: [chain]
|
|
520
|
+
},
|
|
521
|
+
options
|
|
522
|
+
)
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
export { createDepositController, createFundingWithdrawExecutor, createMarketDataProvider, createPredicateMarketPolicyAdapter, createWithdrawController, fetchErc20Balance, fetchFundingTokenBalance, findTokenDataFromChains, isUsdtWithdrawDirect, parseUnits };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getEnv, getChainInfo } from './chunk-YX56ZGDB.js';
|
|
2
|
+
|
|
3
|
+
// ../sign_in_sdk/src/config.ts
|
|
4
|
+
var stage = getEnv("STAGE") || "dev";
|
|
5
|
+
var clientIds = {
|
|
6
|
+
google: getEnv("GOOGLE_CLIENT_ID"),
|
|
7
|
+
x: getEnv("X_CLIENT_ID")
|
|
8
|
+
};
|
|
9
|
+
var chainConfig = {
|
|
10
|
+
chainType: "evm",
|
|
11
|
+
chainId: getChainInfo().chainId
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export { chainConfig, clientIds, stage };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { getEnv } from './chunk-SHLNBZBY.js';
|
|
2
|
+
|
|
3
|
+
// src/constants/chains.ts
|
|
4
|
+
var TENDERLY_BSC_3131 = {
|
|
5
|
+
chainId: "3131",
|
|
6
|
+
name: "BSC_TENDERLY",
|
|
7
|
+
chainName: "BSC_TENDERLY",
|
|
8
|
+
nativeCurrencyName: "BSC",
|
|
9
|
+
nativeCurrencySymbol: "BSC",
|
|
10
|
+
nativeCurrencyDecimals: 18,
|
|
11
|
+
rpcUrls: [
|
|
12
|
+
"https://virtual.binance.eu.rpc.tenderly.co/e643ea28-32eb-4fb9-8116-90be24f7defa"
|
|
13
|
+
],
|
|
14
|
+
blockExplorerUrl: "https://dashboard.tenderly.co/explorer/vnet/6593bc72-f548-497d-bff9-5be061436a48",
|
|
15
|
+
platformType: "EVM",
|
|
16
|
+
icon: "https://static.tomo.inc/token/bsc_new.svg",
|
|
17
|
+
defaultFundingTokenAddress: "0x55d398326f99059fF775485246999027B3197955"
|
|
18
|
+
};
|
|
19
|
+
var BSC_MAINNET_56 = {
|
|
20
|
+
chainId: "56",
|
|
21
|
+
name: "BSC",
|
|
22
|
+
chainName: "BNB Smart Chain",
|
|
23
|
+
nativeCurrencyName: "BNB",
|
|
24
|
+
nativeCurrencySymbol: "BNB",
|
|
25
|
+
nativeCurrencyDecimals: 18,
|
|
26
|
+
rpcUrls: ["https://bsc-dataseed.binance.org", "https://bsc-dataseed1.defibit.io"],
|
|
27
|
+
blockExplorerUrl: "https://bscscan.com",
|
|
28
|
+
platformType: "EVM",
|
|
29
|
+
icon: "https://static.tomo.inc/token/bsc_new.svg",
|
|
30
|
+
defaultFundingTokenAddress: "0x55d398326f99059fF775485246999027B3197955"
|
|
31
|
+
};
|
|
32
|
+
var CHAIN_REGISTRY = {
|
|
33
|
+
[TENDERLY_BSC_3131.chainId]: TENDERLY_BSC_3131,
|
|
34
|
+
[BSC_MAINNET_56.chainId]: BSC_MAINNET_56
|
|
35
|
+
};
|
|
36
|
+
var DEFAULT_FUNDING_CHAIN_ID = getEnv("FUNDING_CHAIN_ID") || "3131";
|
|
37
|
+
function normalizeFundingChainId(chainId) {
|
|
38
|
+
if (chainId === void 0 || chainId === null) return DEFAULT_FUNDING_CHAIN_ID;
|
|
39
|
+
const normalized = String(chainId).trim();
|
|
40
|
+
return normalized === "" ? DEFAULT_FUNDING_CHAIN_ID : normalized;
|
|
41
|
+
}
|
|
42
|
+
function getChainInfo(chainId) {
|
|
43
|
+
const id = normalizeFundingChainId(chainId);
|
|
44
|
+
const info = CHAIN_REGISTRY[id];
|
|
45
|
+
if (!info) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Unsupported funding chainId "${id}". Supported: ${Object.keys(CHAIN_REGISTRY).sort().join(", ")}`
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
return info;
|
|
51
|
+
}
|
|
52
|
+
function pickEnvFundingTokenAddress() {
|
|
53
|
+
const candidates = [["NEXT_PUBLIC_FUNDING_TOKEN_ADDRESS", "FUNDING_TOKEN_ADDRESS"]];
|
|
54
|
+
const processEnv = globalThis.process?.env;
|
|
55
|
+
if (processEnv) {
|
|
56
|
+
for (const [pub, priv] of candidates) {
|
|
57
|
+
const publicValue = processEnv[pub];
|
|
58
|
+
const privateValue = processEnv[priv];
|
|
59
|
+
if (publicValue != null && publicValue !== "") return publicValue;
|
|
60
|
+
if (privateValue != null && privateValue !== "") return privateValue;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const metaEnv = import.meta.env;
|
|
65
|
+
if (metaEnv) {
|
|
66
|
+
for (const [pub, priv] of candidates) {
|
|
67
|
+
const publicValue = metaEnv[pub];
|
|
68
|
+
const privateValue = metaEnv[priv];
|
|
69
|
+
if (publicValue != null && publicValue !== "") return publicValue;
|
|
70
|
+
if (privateValue != null && privateValue !== "") return privateValue;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
}
|
|
75
|
+
return void 0;
|
|
76
|
+
}
|
|
77
|
+
function getFundingTokenAddress(chainId) {
|
|
78
|
+
const fromEnv = pickEnvFundingTokenAddress();
|
|
79
|
+
if (fromEnv && /^0x[0-9a-fA-F]{40}$/.test(fromEnv)) return fromEnv;
|
|
80
|
+
return getChainInfo(chainId).defaultFundingTokenAddress;
|
|
81
|
+
}
|
|
82
|
+
var DEFAULT_FUNDING_TOKEN_ADDRESS = getFundingTokenAddress(DEFAULT_FUNDING_CHAIN_ID);
|
|
83
|
+
var ClientIds = {
|
|
84
|
+
google: getEnv("GOOGLE_CLIENT_ID"),
|
|
85
|
+
x: getEnv("X_CLIENT_ID")
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export { ClientIds, DEFAULT_FUNDING_CHAIN_ID, DEFAULT_FUNDING_TOKEN_ADDRESS, getChainInfo, getFundingTokenAddress };
|