@stablechain/sdk 1.0.3 → 1.0.5
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 +757 -0
- package/dist/chunk-QQ26UI3F.cjs +665 -0
- package/dist/chunk-VS6GBRDF.js +665 -0
- package/dist/erc3009.cjs +26 -0
- package/dist/erc3009.d.cts +429 -0
- package/dist/erc3009.d.ts +429 -0
- package/dist/erc3009.js +26 -0
- package/dist/index.cjs +709 -180
- package/dist/index.d.cts +109 -4
- package/dist/index.d.ts +109 -4
- package/dist/index.js +635 -106
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ERC3009_ABI,
|
|
3
|
+
STABLE_USDT_ADDRESS,
|
|
4
|
+
STABLE_VAULT_ADDRESS,
|
|
5
|
+
StableBulkError,
|
|
6
|
+
StableError,
|
|
7
|
+
StableNetworkError,
|
|
8
|
+
StableQuoteError,
|
|
9
|
+
StableTransactionError,
|
|
10
|
+
StableValidationError,
|
|
11
|
+
cancelAuthorization,
|
|
12
|
+
erc3009Actions,
|
|
13
|
+
getAuthorizationState,
|
|
14
|
+
getAuthorizationUsage,
|
|
15
|
+
prepareTransferWithAuthorization,
|
|
16
|
+
receiveWithAuthorization,
|
|
17
|
+
signReceiveAuthorization,
|
|
18
|
+
signTransferAuthorization,
|
|
19
|
+
transferWithAuthorization,
|
|
20
|
+
verifyAuthorization
|
|
21
|
+
} from "./chunk-VS6GBRDF.js";
|
|
22
|
+
|
|
1
23
|
// src/stable.ts
|
|
2
24
|
import {
|
|
3
|
-
http as
|
|
4
|
-
createPublicClient as
|
|
5
|
-
createWalletClient as
|
|
6
|
-
erc20Abi as
|
|
7
|
-
isAddress as
|
|
8
|
-
parseUnits as
|
|
25
|
+
http as http6,
|
|
26
|
+
createPublicClient as createPublicClient6,
|
|
27
|
+
createWalletClient as createWalletClient5,
|
|
28
|
+
erc20Abi as erc20Abi5,
|
|
29
|
+
isAddress as isAddress5,
|
|
30
|
+
parseUnits as parseUnits5
|
|
9
31
|
} from "viem";
|
|
10
32
|
import { stable as stableMainnet2, stableTestnet as stableTestnet2 } from "viem/chains";
|
|
11
33
|
|
|
@@ -25,85 +47,6 @@ import {
|
|
|
25
47
|
parseUnits
|
|
26
48
|
} from "viem";
|
|
27
49
|
|
|
28
|
-
// src/errors.ts
|
|
29
|
-
import { BaseError } from "viem";
|
|
30
|
-
var StableError = class extends BaseError {
|
|
31
|
-
};
|
|
32
|
-
var StableValidationError = class extends StableError {
|
|
33
|
-
constructor(field, value, reason, opts) {
|
|
34
|
-
super(reason, {
|
|
35
|
-
name: "StableValidationError",
|
|
36
|
-
cause: opts?.cause,
|
|
37
|
-
metaMessages: [`Field: ${field}`, `Value: ${formatValue(value)}`]
|
|
38
|
-
});
|
|
39
|
-
this.field = field;
|
|
40
|
-
this.value = value;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
var StableQuoteError = class extends StableError {
|
|
44
|
-
constructor(args) {
|
|
45
|
-
const meta = [`Provider: ${args.provider}`];
|
|
46
|
-
if (args.httpStatus !== void 0)
|
|
47
|
-
meta.push(`HTTP status: ${args.httpStatus}`);
|
|
48
|
-
if (args.providerCode) meta.push(`Provider code: ${args.providerCode}`);
|
|
49
|
-
super(args.shortMessage, {
|
|
50
|
-
name: "StableQuoteError",
|
|
51
|
-
cause: args.cause,
|
|
52
|
-
metaMessages: meta
|
|
53
|
-
});
|
|
54
|
-
this.provider = args.provider;
|
|
55
|
-
this.httpStatus = args.httpStatus;
|
|
56
|
-
this.providerCode = args.providerCode;
|
|
57
|
-
this.body = args.body;
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
var StableTransactionError = class extends StableError {
|
|
61
|
-
constructor(args) {
|
|
62
|
-
const meta = [`Phase: ${args.phase}`];
|
|
63
|
-
if (args.chainId !== void 0) meta.push(`Chain ID: ${args.chainId}`);
|
|
64
|
-
if (args.txHash) meta.push(`Tx hash: ${args.txHash}`);
|
|
65
|
-
if (args.revertReason) meta.push(`Revert reason: ${args.revertReason}`);
|
|
66
|
-
super(args.shortMessage, {
|
|
67
|
-
name: "StableTransactionError",
|
|
68
|
-
cause: args.cause,
|
|
69
|
-
metaMessages: meta
|
|
70
|
-
});
|
|
71
|
-
this.phase = args.phase;
|
|
72
|
-
this.txHash = args.txHash;
|
|
73
|
-
this.chainId = args.chainId;
|
|
74
|
-
this.revertReason = args.revertReason;
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
var StableNetworkError = class extends StableError {
|
|
78
|
-
constructor(args) {
|
|
79
|
-
super(args.shortMessage, {
|
|
80
|
-
name: "StableNetworkError",
|
|
81
|
-
cause: args.cause,
|
|
82
|
-
metaMessages: args.url ? [`URL: ${args.url}`] : void 0
|
|
83
|
-
});
|
|
84
|
-
this.url = args.url;
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
var StableBulkError = class extends StableError {
|
|
88
|
-
constructor(args) {
|
|
89
|
-
super(args.shortMessage, { name: "StableBulkError" });
|
|
90
|
-
this.results = args.results;
|
|
91
|
-
this.succeeded = args.succeeded;
|
|
92
|
-
this.failed = args.failed;
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
function formatValue(v) {
|
|
96
|
-
if (typeof v === "bigint") return `${v}n`;
|
|
97
|
-
if (typeof v === "string") return JSON.stringify(v);
|
|
98
|
-
if (v === null) return "null";
|
|
99
|
-
if (v === void 0) return "undefined";
|
|
100
|
-
try {
|
|
101
|
-
return JSON.stringify(v);
|
|
102
|
-
} catch {
|
|
103
|
-
return String(v);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
50
|
// src/helpers/chain.ts
|
|
108
51
|
import { defineChain } from "viem";
|
|
109
52
|
function makeChain(id, rpc) {
|
|
@@ -819,6 +762,14 @@ var Chain = /* @__PURE__ */ ((Chain2) => {
|
|
|
819
762
|
Chain2["Base"] = "base";
|
|
820
763
|
Chain2["BSC"] = "bsc";
|
|
821
764
|
Chain2["HyperEVM"] = "hyperevm";
|
|
765
|
+
Chain2["Polygon"] = "polygon";
|
|
766
|
+
Chain2["Plasma"] = "plasma";
|
|
767
|
+
Chain2["Optimism"] = "optimism";
|
|
768
|
+
Chain2["Unichain"] = "unichain";
|
|
769
|
+
Chain2["Sei"] = "sei";
|
|
770
|
+
Chain2["Flare"] = "flare";
|
|
771
|
+
Chain2["XLayer"] = "xlayer";
|
|
772
|
+
Chain2["Rootstock"] = "rootstock";
|
|
822
773
|
return Chain2;
|
|
823
774
|
})(Chain || {});
|
|
824
775
|
var Network = /* @__PURE__ */ ((Network2) => {
|
|
@@ -1259,7 +1210,7 @@ var CHAIN_CONFIGS = {
|
|
|
1259
1210
|
id: 11155111,
|
|
1260
1211
|
rpc: "https://ethereum-sepolia-rpc.publicnode.com",
|
|
1261
1212
|
usdt: "0xc4DCC311c028e341fd8602D8eB89c5de94625927",
|
|
1262
|
-
decimals:
|
|
1213
|
+
decimals: 6
|
|
1263
1214
|
},
|
|
1264
1215
|
["stable-testnet" /* StableTestnet */]: {
|
|
1265
1216
|
id: 2201,
|
|
@@ -1277,13 +1228,15 @@ var CHAIN_CONFIGS = {
|
|
|
1277
1228
|
["ethereum" /* Ethereum */]: {
|
|
1278
1229
|
id: 1,
|
|
1279
1230
|
rpc: "https://ethereum-rpc.publicnode.com",
|
|
1280
|
-
|
|
1231
|
+
// Canonical USDT. Not the OFT adapter — this field is used as an ERC-20
|
|
1232
|
+
// (allowance/approve/balanceOf) and as the token address for LI.FI.
|
|
1233
|
+
usdt: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
1281
1234
|
decimals: 6
|
|
1282
1235
|
},
|
|
1283
1236
|
["arbitrum" /* Arbitrum */]: {
|
|
1284
1237
|
id: 42161,
|
|
1285
1238
|
rpc: "https://arbitrum-one-rpc.publicnode.com",
|
|
1286
|
-
usdt: "
|
|
1239
|
+
usdt: "0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9",
|
|
1287
1240
|
decimals: 6
|
|
1288
1241
|
},
|
|
1289
1242
|
["ink" /* Ink */]: {
|
|
@@ -1300,7 +1253,7 @@ var CHAIN_CONFIGS = {
|
|
|
1300
1253
|
},
|
|
1301
1254
|
["megaeth" /* MegaETH */]: {
|
|
1302
1255
|
id: 4326,
|
|
1303
|
-
rpc: "https://
|
|
1256
|
+
rpc: "https://mainnet.megaeth.com/rpc",
|
|
1304
1257
|
usdt: "0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb",
|
|
1305
1258
|
decimals: 6
|
|
1306
1259
|
},
|
|
@@ -1321,6 +1274,55 @@ var CHAIN_CONFIGS = {
|
|
|
1321
1274
|
rpc: "https://rpc.hyperliquid.xyz/evm",
|
|
1322
1275
|
usdt: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
|
|
1323
1276
|
decimals: 6
|
|
1277
|
+
},
|
|
1278
|
+
["polygon" /* Polygon */]: {
|
|
1279
|
+
id: 137,
|
|
1280
|
+
rpc: "https://polygon-bor-rpc.publicnode.com",
|
|
1281
|
+
// Polygon's canonical USDT, migrated to USDT0
|
|
1282
|
+
usdt: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F",
|
|
1283
|
+
decimals: 6
|
|
1284
|
+
},
|
|
1285
|
+
["plasma" /* Plasma */]: {
|
|
1286
|
+
id: 9745,
|
|
1287
|
+
rpc: "https://rpc.plasma.to",
|
|
1288
|
+
usdt: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb",
|
|
1289
|
+
decimals: 6
|
|
1290
|
+
},
|
|
1291
|
+
["optimism" /* Optimism */]: {
|
|
1292
|
+
id: 10,
|
|
1293
|
+
rpc: "https://optimism-rpc.publicnode.com",
|
|
1294
|
+
usdt: "0x01bFF41798a0BcF287b996046Ca68b395DbC1071",
|
|
1295
|
+
decimals: 6
|
|
1296
|
+
},
|
|
1297
|
+
["unichain" /* Unichain */]: {
|
|
1298
|
+
id: 130,
|
|
1299
|
+
rpc: "https://unichain-rpc.publicnode.com",
|
|
1300
|
+
usdt: "0x9151434b16b9763660705744891fA906F660EcC5",
|
|
1301
|
+
decimals: 6
|
|
1302
|
+
},
|
|
1303
|
+
["sei" /* Sei */]: {
|
|
1304
|
+
id: 1329,
|
|
1305
|
+
rpc: "https://sei-evm-rpc.publicnode.com",
|
|
1306
|
+
usdt: "0x9151434b16b9763660705744891fA906F660EcC5",
|
|
1307
|
+
decimals: 6
|
|
1308
|
+
},
|
|
1309
|
+
["flare" /* Flare */]: {
|
|
1310
|
+
id: 14,
|
|
1311
|
+
rpc: "https://flare-api.flare.network/ext/C/rpc",
|
|
1312
|
+
usdt: "0xe7cd86e13AC4309349F30B3435a9d337750fC82D",
|
|
1313
|
+
decimals: 6
|
|
1314
|
+
},
|
|
1315
|
+
["xlayer" /* XLayer */]: {
|
|
1316
|
+
id: 196,
|
|
1317
|
+
rpc: "https://rpc.xlayer.tech",
|
|
1318
|
+
usdt: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736",
|
|
1319
|
+
decimals: 6
|
|
1320
|
+
},
|
|
1321
|
+
["rootstock" /* Rootstock */]: {
|
|
1322
|
+
id: 30,
|
|
1323
|
+
rpc: "https://public-node.rsk.co",
|
|
1324
|
+
usdt: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736",
|
|
1325
|
+
decimals: 6
|
|
1324
1326
|
}
|
|
1325
1327
|
};
|
|
1326
1328
|
|
|
@@ -1723,14 +1725,522 @@ function isLiFiQuoteShape(v) {
|
|
|
1723
1725
|
return isObject(tx) && typeof tx.to === "string" && typeof tx.data === "string" && typeof tx.chainId === "number" && isObject(est) && typeof est.fromAmount === "string" && typeof est.toAmount === "string" && isObject(act) && isObject(act.fromToken) && isObject(act.toToken);
|
|
1724
1726
|
}
|
|
1725
1727
|
|
|
1728
|
+
// src/services/layerzero.ts
|
|
1729
|
+
import {
|
|
1730
|
+
concat,
|
|
1731
|
+
createPublicClient as createPublicClient5,
|
|
1732
|
+
createWalletClient as createWalletClient4,
|
|
1733
|
+
erc20Abi as erc20Abi4,
|
|
1734
|
+
http as http5,
|
|
1735
|
+
isAddress as isAddress4,
|
|
1736
|
+
numberToHex,
|
|
1737
|
+
padHex,
|
|
1738
|
+
parseUnits as parseUnits4
|
|
1739
|
+
} from "viem";
|
|
1740
|
+
var C = CHAIN_CONFIGS;
|
|
1741
|
+
var BRIDGE_CHAIN_CONFIGS = {
|
|
1742
|
+
// ─── Testnet ───────────────────────────────────────────────────────────────
|
|
1743
|
+
["sepolia" /* Sepolia */]: { ...C["sepolia" /* Sepolia */], lzEid: 40161, oftAdapter: "0xc099cD946d5efCC35A99D64E808c1430cEf08126", blockTimeSec: 12 },
|
|
1744
|
+
["stable-testnet" /* StableTestnet */]: { ...C["stable-testnet" /* StableTestnet */], lzEid: 40374, oftAdapter: "0x779Ded0c9e1022225f8E0630b35a9b54bE713736", blockTimeSec: 0.7 },
|
|
1745
|
+
// ─── Mainnet ──────────────────────────────────────────────────────────────
|
|
1746
|
+
["stable" /* Stable */]: { ...C["stable" /* Stable */], lzEid: 30396, oftAdapter: "0xedaba024be4d87974d5aB11C6Dd586963CcCB027", blockTimeSec: 0.7 },
|
|
1747
|
+
["ethereum" /* Ethereum */]: { ...C["ethereum" /* Ethereum */], lzEid: 30101, oftAdapter: "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee", blockTimeSec: 12 },
|
|
1748
|
+
["arbitrum" /* Arbitrum */]: { ...C["arbitrum" /* Arbitrum */], lzEid: 30110, oftAdapter: "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92", blockTimeSec: 0.25 },
|
|
1749
|
+
["ink" /* Ink */]: { ...C["ink" /* Ink */], lzEid: 30339, oftAdapter: "0x1cB6De532588fCA4a21B7209DE7C456AF8434A65", blockTimeSec: 1 },
|
|
1750
|
+
["bera" /* Bera */]: { ...C["bera" /* Bera */], lzEid: 30362, oftAdapter: "0x3Dc96399109df5ceb2C226664A086140bD0379cB", blockTimeSec: 2 },
|
|
1751
|
+
["megaeth" /* MegaETH */]: { ...C["megaeth" /* MegaETH */], lzEid: 30398, oftAdapter: "0x9151434b16b9763660705744891fa906f660ecc5", blockTimeSec: 1 },
|
|
1752
|
+
["hyperevm" /* HyperEVM */]: { ...C["hyperevm" /* HyperEVM */], lzEid: 30367, oftAdapter: "0x904861a24F30EC96ea7CFC3bE9EA4B476d237e98", blockTimeSec: 1 },
|
|
1753
|
+
["polygon" /* Polygon */]: { ...C["polygon" /* Polygon */], lzEid: 30109, oftAdapter: "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13", blockTimeSec: 1.5 },
|
|
1754
|
+
["plasma" /* Plasma */]: { ...C["plasma" /* Plasma */], lzEid: 30383, oftAdapter: "0x02ca37966753bDdDf11216B73B16C1dE756A7CF9", blockTimeSec: 1 },
|
|
1755
|
+
["optimism" /* Optimism */]: { ...C["optimism" /* Optimism */], lzEid: 30111, oftAdapter: "0xF03b4d9AC1D5d1E7c4cEf54C2A313b9fe051A0aD", blockTimeSec: 2 },
|
|
1756
|
+
["unichain" /* Unichain */]: { ...C["unichain" /* Unichain */], lzEid: 30320, oftAdapter: "0xc07bE8994D035631c36fb4a89C918CeFB2f03EC3", blockTimeSec: 1 },
|
|
1757
|
+
["sei" /* Sei */]: { ...C["sei" /* Sei */], lzEid: 30280, oftAdapter: "0x56Fe74A2e3b484b921c447357203431a3485CC60", blockTimeSec: 0.5 },
|
|
1758
|
+
["flare" /* Flare */]: { ...C["flare" /* Flare */], lzEid: 30295, oftAdapter: "0x567287d2A9829215a37e3B88843d32f9221E7588", blockTimeSec: 1.1 },
|
|
1759
|
+
["xlayer" /* XLayer */]: { ...C["xlayer" /* XLayer */], lzEid: 30274, oftAdapter: "0x94BCCa6bdfd6A61817Ab0E960bFedE4984505554", blockTimeSec: 1 },
|
|
1760
|
+
["rootstock" /* Rootstock */]: { ...C["rootstock" /* Rootstock */], lzEid: 30333, oftAdapter: "0x1a594d5d5d1c426281C1064B07f23F57B2716B61", blockTimeSec: 31 }
|
|
1761
|
+
};
|
|
1762
|
+
var OFT_ADAPTER_ABI = [
|
|
1763
|
+
{
|
|
1764
|
+
name: "quoteSend",
|
|
1765
|
+
type: "function",
|
|
1766
|
+
inputs: [
|
|
1767
|
+
{
|
|
1768
|
+
name: "_sendParam",
|
|
1769
|
+
type: "tuple",
|
|
1770
|
+
components: [
|
|
1771
|
+
{ name: "dstEid", type: "uint32" },
|
|
1772
|
+
{ name: "to", type: "bytes32" },
|
|
1773
|
+
{ name: "amountLD", type: "uint256" },
|
|
1774
|
+
{ name: "minAmountLD", type: "uint256" },
|
|
1775
|
+
{ name: "extraOptions", type: "bytes" },
|
|
1776
|
+
{ name: "composeMsg", type: "bytes" },
|
|
1777
|
+
{ name: "oftCmd", type: "bytes" }
|
|
1778
|
+
]
|
|
1779
|
+
},
|
|
1780
|
+
{ name: "_payInLzToken", type: "bool" }
|
|
1781
|
+
],
|
|
1782
|
+
outputs: [
|
|
1783
|
+
{
|
|
1784
|
+
name: "msgFee",
|
|
1785
|
+
type: "tuple",
|
|
1786
|
+
components: [
|
|
1787
|
+
{ name: "nativeFee", type: "uint256" },
|
|
1788
|
+
{ name: "lzTokenFee", type: "uint256" }
|
|
1789
|
+
]
|
|
1790
|
+
}
|
|
1791
|
+
],
|
|
1792
|
+
stateMutability: "view"
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
name: "send",
|
|
1796
|
+
type: "function",
|
|
1797
|
+
inputs: [
|
|
1798
|
+
{
|
|
1799
|
+
name: "_sendParam",
|
|
1800
|
+
type: "tuple",
|
|
1801
|
+
components: [
|
|
1802
|
+
{ name: "dstEid", type: "uint32" },
|
|
1803
|
+
{ name: "to", type: "bytes32" },
|
|
1804
|
+
{ name: "amountLD", type: "uint256" },
|
|
1805
|
+
{ name: "minAmountLD", type: "uint256" },
|
|
1806
|
+
{ name: "extraOptions", type: "bytes" },
|
|
1807
|
+
{ name: "composeMsg", type: "bytes" },
|
|
1808
|
+
{ name: "oftCmd", type: "bytes" }
|
|
1809
|
+
]
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
name: "_fee",
|
|
1813
|
+
type: "tuple",
|
|
1814
|
+
components: [
|
|
1815
|
+
{ name: "nativeFee", type: "uint256" },
|
|
1816
|
+
{ name: "lzTokenFee", type: "uint256" }
|
|
1817
|
+
]
|
|
1818
|
+
},
|
|
1819
|
+
{ name: "_refundAddress", type: "address" }
|
|
1820
|
+
],
|
|
1821
|
+
outputs: [],
|
|
1822
|
+
stateMutability: "payable"
|
|
1823
|
+
}
|
|
1824
|
+
];
|
|
1825
|
+
var OAPP_ABI = [
|
|
1826
|
+
{ name: "endpoint", type: "function", stateMutability: "view", inputs: [], outputs: [{ type: "address" }] }
|
|
1827
|
+
];
|
|
1828
|
+
var ENDPOINT_V2_ABI = [
|
|
1829
|
+
{
|
|
1830
|
+
name: "getSendLibrary",
|
|
1831
|
+
type: "function",
|
|
1832
|
+
stateMutability: "view",
|
|
1833
|
+
inputs: [{ name: "_sender", type: "address" }, { name: "_dstEid", type: "uint32" }],
|
|
1834
|
+
outputs: [{ type: "address" }]
|
|
1835
|
+
}
|
|
1836
|
+
];
|
|
1837
|
+
var SEND_ULN_ABI = [
|
|
1838
|
+
{
|
|
1839
|
+
name: "getUlnConfig",
|
|
1840
|
+
type: "function",
|
|
1841
|
+
stateMutability: "view",
|
|
1842
|
+
inputs: [{ name: "_oapp", type: "address" }, { name: "_remoteEid", type: "uint32" }],
|
|
1843
|
+
outputs: [
|
|
1844
|
+
{
|
|
1845
|
+
name: "rtnConfig",
|
|
1846
|
+
type: "tuple",
|
|
1847
|
+
components: [
|
|
1848
|
+
{ name: "confirmations", type: "uint64" },
|
|
1849
|
+
{ name: "requiredDVNCount", type: "uint8" },
|
|
1850
|
+
{ name: "optionalDVNCount", type: "uint8" },
|
|
1851
|
+
{ name: "optionalDVNThreshold", type: "uint8" },
|
|
1852
|
+
{ name: "requiredDVNs", type: "address[]" },
|
|
1853
|
+
{ name: "optionalDVNs", type: "address[]" }
|
|
1854
|
+
]
|
|
1855
|
+
}
|
|
1856
|
+
]
|
|
1857
|
+
}
|
|
1858
|
+
];
|
|
1859
|
+
var LZ_SCAN_API = "https://scan.layerzero-api.com/v1";
|
|
1860
|
+
var LZ_SCAN_UI = "https://layerzeroscan.com";
|
|
1861
|
+
var CACHE_TTL_MS = 5 * 6e4;
|
|
1862
|
+
var cache = /* @__PURE__ */ new Map();
|
|
1863
|
+
function clearBridgeEstimateCache() {
|
|
1864
|
+
cache.clear();
|
|
1865
|
+
}
|
|
1866
|
+
async function cached(key, ttlMs, load) {
|
|
1867
|
+
const hit = cache.get(key);
|
|
1868
|
+
if (hit && Date.now() - hit.at < ttlMs) return hit.value;
|
|
1869
|
+
const value = await load();
|
|
1870
|
+
cache.set(key, { at: Date.now(), value });
|
|
1871
|
+
return value;
|
|
1872
|
+
}
|
|
1873
|
+
var ScanHttpError = class extends Error {
|
|
1874
|
+
constructor(status, path) {
|
|
1875
|
+
super(`LayerZero Scan ${status} for ${path}`);
|
|
1876
|
+
this.status = status;
|
|
1877
|
+
this.name = "ScanHttpError";
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
async function scanFetch(path, timeoutMs = 8e3) {
|
|
1881
|
+
const res = await fetch(`${LZ_SCAN_API}${path}`, { signal: AbortSignal.timeout(timeoutMs) });
|
|
1882
|
+
if (!res.ok) throw new ScanHttpError(res.status, path);
|
|
1883
|
+
return res.json();
|
|
1884
|
+
}
|
|
1885
|
+
var TERMINAL_FAILURE_STATUSES = /* @__PURE__ */ new Set([
|
|
1886
|
+
"FAILED",
|
|
1887
|
+
"BLOCKED",
|
|
1888
|
+
"PAYLOAD_STORED",
|
|
1889
|
+
"APPLICATION_BURNED",
|
|
1890
|
+
"APPLICATION_SKIPPED",
|
|
1891
|
+
"UNRESOLVABLE_COMMAND",
|
|
1892
|
+
"MALFORMED_COMMAND"
|
|
1893
|
+
]);
|
|
1894
|
+
function median(values) {
|
|
1895
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
1896
|
+
const mid = Math.floor(sorted.length / 2);
|
|
1897
|
+
return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
1898
|
+
}
|
|
1899
|
+
function buildLzOptions(gasLimit = 0n) {
|
|
1900
|
+
return concat([
|
|
1901
|
+
numberToHex(3, { size: 2 }),
|
|
1902
|
+
// TYPE_3 header
|
|
1903
|
+
numberToHex(1, { size: 1 }),
|
|
1904
|
+
// Executor worker ID
|
|
1905
|
+
numberToHex(17, { size: 2 }),
|
|
1906
|
+
// option payload length = 17 bytes
|
|
1907
|
+
numberToHex(1, { size: 1 }),
|
|
1908
|
+
// LzReceive option type
|
|
1909
|
+
numberToHex(gasLimit, { size: 16 })
|
|
1910
|
+
// gas limit as uint128
|
|
1911
|
+
]);
|
|
1912
|
+
}
|
|
1913
|
+
var LayerZeroService = class {
|
|
1914
|
+
constructor(config) {
|
|
1915
|
+
this.config = config;
|
|
1916
|
+
}
|
|
1917
|
+
async quoteBridge(params) {
|
|
1918
|
+
const [fee, estimate] = await Promise.all([
|
|
1919
|
+
this.quoteFee(params, "quoteBridge"),
|
|
1920
|
+
this.estimateBridgeTime(params).catch(() => void 0)
|
|
1921
|
+
]);
|
|
1922
|
+
return { ...fee, toAmount: params.amount, estimate };
|
|
1923
|
+
}
|
|
1924
|
+
/**
|
|
1925
|
+
* LayerZero messaging fee for a send, with no delivery estimate attached — the
|
|
1926
|
+
* send path needs the fee and nothing else, and must not wait on Scan for it.
|
|
1927
|
+
*/
|
|
1928
|
+
async quoteFee({ fromChain, toChain, fromToken, toToken, amount, recipient }, method) {
|
|
1929
|
+
const recipientAddr = recipient ?? "0x0000000000000000000000000000000000000000";
|
|
1930
|
+
this.validateBridgeParams({ fromChain, toChain, amount, recipient: recipientAddr }, method);
|
|
1931
|
+
const { src, dst } = this.resolveChains(fromChain, toChain, fromToken, toToken);
|
|
1932
|
+
const oftAdapter = src.oftAdapter;
|
|
1933
|
+
const amountLD = parseUnits4(String(amount), src.decimals);
|
|
1934
|
+
try {
|
|
1935
|
+
const { nativeFee, lzTokenFee } = await createPublicClient5({
|
|
1936
|
+
chain: makeChain(src.id, src.rpc),
|
|
1937
|
+
transport: http5(src.rpc)
|
|
1938
|
+
}).readContract({
|
|
1939
|
+
address: oftAdapter,
|
|
1940
|
+
abi: OFT_ADAPTER_ABI,
|
|
1941
|
+
functionName: "quoteSend",
|
|
1942
|
+
args: [this.buildSendParams(dst, amountLD, recipientAddr), false]
|
|
1943
|
+
});
|
|
1944
|
+
return { nativeFee, lzTokenFee };
|
|
1945
|
+
} catch (err) {
|
|
1946
|
+
throw new StableQuoteError({
|
|
1947
|
+
provider: "layerzero",
|
|
1948
|
+
shortMessage: `${method}: quoteSend call failed`,
|
|
1949
|
+
cause: err
|
|
1950
|
+
});
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
async bridge({ fromChain, toChain, fromToken, toToken, amount, recipient, quote }) {
|
|
1954
|
+
const from = this.config.walletClient?.account?.address ?? this.config.account?.address;
|
|
1955
|
+
if (!from) {
|
|
1956
|
+
throw new StableValidationError(
|
|
1957
|
+
"signer",
|
|
1958
|
+
void 0,
|
|
1959
|
+
"bridge: requires a signer \u2014 set walletClient or account in StableConfig"
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
const recipientAddr = recipient ?? from;
|
|
1963
|
+
this.validateBridgeParams({ fromChain, toChain, amount, recipient: recipientAddr }, "bridge");
|
|
1964
|
+
const { src, dst } = this.resolveChains(fromChain, toChain, fromToken, toToken);
|
|
1965
|
+
const oftAdapter = src.oftAdapter;
|
|
1966
|
+
const srcChain = makeChain(src.id, src.rpc);
|
|
1967
|
+
const wc = this.config.walletClient ?? createWalletClient4({
|
|
1968
|
+
account: this.config.account,
|
|
1969
|
+
chain: srcChain,
|
|
1970
|
+
transport: this.config.transport ?? http5(src.rpc)
|
|
1971
|
+
});
|
|
1972
|
+
const pc = createPublicClient5({ chain: srcChain, transport: http5(src.rpc) });
|
|
1973
|
+
try {
|
|
1974
|
+
await wc.switchChain({ id: src.id });
|
|
1975
|
+
} catch (err) {
|
|
1976
|
+
throw new StableTransactionError({
|
|
1977
|
+
phase: "switch_chain",
|
|
1978
|
+
shortMessage: `bridge: wallet rejected or failed to switch to chain ${src.id}`,
|
|
1979
|
+
chainId: src.id,
|
|
1980
|
+
cause: err
|
|
1981
|
+
});
|
|
1982
|
+
}
|
|
1983
|
+
const amountLD = parseUnits4(String(amount), src.decimals);
|
|
1984
|
+
const sendParams = this.buildSendParams(dst, amountLD, recipientAddr);
|
|
1985
|
+
const { nativeFee, lzTokenFee } = quote?.nativeFee !== void 0 && quote?.lzTokenFee !== void 0 ? { nativeFee: quote.nativeFee, lzTokenFee: quote.lzTokenFee } : await this.quoteFee({ fromChain, toChain, fromToken, toToken, amount, recipient: recipientAddr }, "bridge");
|
|
1986
|
+
const allowance = await pc.readContract({
|
|
1987
|
+
address: src.usdt,
|
|
1988
|
+
abi: erc20Abi4,
|
|
1989
|
+
functionName: "allowance",
|
|
1990
|
+
args: [from, oftAdapter]
|
|
1991
|
+
});
|
|
1992
|
+
if (allowance < amountLD) {
|
|
1993
|
+
let approveHash;
|
|
1994
|
+
try {
|
|
1995
|
+
approveHash = await wc.writeContract({
|
|
1996
|
+
address: src.usdt,
|
|
1997
|
+
abi: erc20Abi4,
|
|
1998
|
+
functionName: "approve",
|
|
1999
|
+
args: [oftAdapter, amountLD],
|
|
2000
|
+
account: wc.account,
|
|
2001
|
+
chain: srcChain
|
|
2002
|
+
});
|
|
2003
|
+
} catch (err) {
|
|
2004
|
+
throw new StableTransactionError({
|
|
2005
|
+
phase: "approve",
|
|
2006
|
+
shortMessage: "bridge: USDT0 approve failed",
|
|
2007
|
+
chainId: src.id,
|
|
2008
|
+
cause: err
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
const approveReceipt = await pc.waitForTransactionReceipt({ hash: approveHash });
|
|
2012
|
+
if (approveReceipt.status === "reverted") {
|
|
2013
|
+
throw new StableTransactionError({
|
|
2014
|
+
phase: "approve",
|
|
2015
|
+
shortMessage: "bridge: USDT0 approve reverted on-chain",
|
|
2016
|
+
txHash: approveReceipt.transactionHash,
|
|
2017
|
+
chainId: src.id
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
try {
|
|
2022
|
+
const hash = await wc.writeContract({
|
|
2023
|
+
address: oftAdapter,
|
|
2024
|
+
abi: OFT_ADAPTER_ABI,
|
|
2025
|
+
functionName: "send",
|
|
2026
|
+
args: [sendParams, { nativeFee, lzTokenFee }, from],
|
|
2027
|
+
value: nativeFee,
|
|
2028
|
+
account: wc.account,
|
|
2029
|
+
chain: srcChain
|
|
2030
|
+
});
|
|
2031
|
+
return { txHash: hash, toAmount: amount };
|
|
2032
|
+
} catch (err) {
|
|
2033
|
+
throw new StableTransactionError({
|
|
2034
|
+
phase: "send",
|
|
2035
|
+
shortMessage: "bridge: OFT send failed",
|
|
2036
|
+
chainId: src.id,
|
|
2037
|
+
cause: err
|
|
2038
|
+
});
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
/**
|
|
2042
|
+
* Estimate how long a USDT0 bridge will take, end to end.
|
|
2043
|
+
*
|
|
2044
|
+
* Two independent inputs, both cheap:
|
|
2045
|
+
* - **observed** — median delivery time of recent messages LayerZero Scan has
|
|
2046
|
+
* already settled on this exact pathway.
|
|
2047
|
+
* - **formula** — LayerZero's documented estimate from the on-chain ULN config:
|
|
2048
|
+
* `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`.
|
|
2049
|
+
*
|
|
2050
|
+
* `observed` wins when available. The formula assumes `confirmations` is the whole
|
|
2051
|
+
* wait, which holds for L1 sources but badly understates rollups: Arbitrum→Stable
|
|
2052
|
+
* computes to ~15s (60 blocks × 0.25s) while real deliveries take ~18min, because
|
|
2053
|
+
* the DVNs wait for the L2 batch to finalize on L1.
|
|
2054
|
+
*/
|
|
2055
|
+
async estimateBridgeTime({ fromChain, toChain }) {
|
|
2056
|
+
const src = BRIDGE_CHAIN_CONFIGS[fromChain];
|
|
2057
|
+
const dst = BRIDGE_CHAIN_CONFIGS[toChain];
|
|
2058
|
+
if (!src?.oftAdapter) {
|
|
2059
|
+
throw new StableValidationError("fromChain", fromChain, `estimateBridgeTime: no OFT adapter for "${fromChain}"`);
|
|
2060
|
+
}
|
|
2061
|
+
if (!dst?.oftAdapter) {
|
|
2062
|
+
throw new StableValidationError("toChain", toChain, `estimateBridgeTime: no OFT adapter for "${toChain}"`);
|
|
2063
|
+
}
|
|
2064
|
+
const [uln, observedSeconds] = await Promise.all([
|
|
2065
|
+
this.getUlnConfig(src, dst).catch(() => void 0),
|
|
2066
|
+
this.observedBridgeSeconds(src, dst).catch(() => void 0)
|
|
2067
|
+
]);
|
|
2068
|
+
const dvnCount = uln ? uln.requiredDVNCount + uln.optionalDVNCount : void 0;
|
|
2069
|
+
let formulaSeconds;
|
|
2070
|
+
if (uln && dvnCount !== void 0 && src.blockTimeSec && dst.blockTimeSec) {
|
|
2071
|
+
const computed = Math.round(
|
|
2072
|
+
uln.confirmations * src.blockTimeSec + dst.blockTimeSec * (2 + dvnCount)
|
|
2073
|
+
);
|
|
2074
|
+
formulaSeconds = Number.isFinite(computed) ? computed : void 0;
|
|
2075
|
+
}
|
|
2076
|
+
const seconds = observedSeconds ?? formulaSeconds;
|
|
2077
|
+
if (seconds === void 0) {
|
|
2078
|
+
throw new StableQuoteError({
|
|
2079
|
+
provider: "layerzero",
|
|
2080
|
+
shortMessage: `estimateBridgeTime: no pathway data for ${fromChain}\u2192${toChain}`
|
|
2081
|
+
});
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
seconds,
|
|
2085
|
+
source: observedSeconds !== void 0 ? "observed" : "formula",
|
|
2086
|
+
observedSeconds,
|
|
2087
|
+
formulaSeconds,
|
|
2088
|
+
confirmations: Number.isFinite(uln?.confirmations) ? uln?.confirmations : void 0,
|
|
2089
|
+
dvnCount: Number.isFinite(dvnCount) ? dvnCount : void 0
|
|
2090
|
+
};
|
|
2091
|
+
}
|
|
2092
|
+
/**
|
|
2093
|
+
* Follow an in-flight bridge by its source transaction hash. Poll this after
|
|
2094
|
+
* `bridge()` to drive a progress UI; a message LayerZero Scan has not indexed
|
|
2095
|
+
* yet reports `"pending"` rather than throwing.
|
|
2096
|
+
*/
|
|
2097
|
+
async trackBridge(srcTxHash) {
|
|
2098
|
+
const scanUrl = `${LZ_SCAN_UI}/tx/${srcTxHash}`;
|
|
2099
|
+
let message;
|
|
2100
|
+
try {
|
|
2101
|
+
message = (await scanFetch(`/messages/tx/${srcTxHash}`))?.data?.[0];
|
|
2102
|
+
} catch (err) {
|
|
2103
|
+
if (err instanceof ScanHttpError && err.status === 404) {
|
|
2104
|
+
return { state: "pending", srcTxHash, scanUrl };
|
|
2105
|
+
}
|
|
2106
|
+
throw new StableQuoteError({
|
|
2107
|
+
provider: "layerzero",
|
|
2108
|
+
shortMessage: `trackBridge: LayerZero Scan lookup failed for ${srcTxHash}`,
|
|
2109
|
+
cause: err
|
|
2110
|
+
});
|
|
2111
|
+
}
|
|
2112
|
+
if (!message) return { state: "pending", srcTxHash, scanUrl };
|
|
2113
|
+
const raw = message.status?.name ?? "";
|
|
2114
|
+
const sentAt = message.source?.tx?.blockTimestamp;
|
|
2115
|
+
return {
|
|
2116
|
+
// Everything terminal that is not DELIVERED means the tokens will not land
|
|
2117
|
+
// on their own; `raw` carries which of those it was.
|
|
2118
|
+
state: raw === "DELIVERED" ? "delivered" : TERMINAL_FAILURE_STATUSES.has(raw) ? "failed" : "inflight",
|
|
2119
|
+
raw,
|
|
2120
|
+
srcTxHash,
|
|
2121
|
+
dstTxHash: message.destination?.tx?.txHash,
|
|
2122
|
+
elapsedSeconds: sentAt ? Math.max(0, Math.floor(Date.now() / 1e3) - sentAt) : void 0,
|
|
2123
|
+
scanUrl
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
/** Effective ULN config the DVNs enforce for this pathway, read from the source chain. */
|
|
2127
|
+
async getUlnConfig(src, dst) {
|
|
2128
|
+
return cached(`uln:${src.lzEid}-${dst.lzEid}`, CACHE_TTL_MS, async () => {
|
|
2129
|
+
const pc = createPublicClient5({ chain: makeChain(src.id, src.rpc), transport: http5(src.rpc) });
|
|
2130
|
+
const oapp = src.oftAdapter;
|
|
2131
|
+
const endpoint = await pc.readContract({ address: oapp, abi: OAPP_ABI, functionName: "endpoint" });
|
|
2132
|
+
const sendLib = await pc.readContract({
|
|
2133
|
+
address: endpoint,
|
|
2134
|
+
abi: ENDPOINT_V2_ABI,
|
|
2135
|
+
functionName: "getSendLibrary",
|
|
2136
|
+
args: [oapp, dst.lzEid]
|
|
2137
|
+
});
|
|
2138
|
+
const cfg = await pc.readContract({
|
|
2139
|
+
address: sendLib,
|
|
2140
|
+
abi: SEND_ULN_ABI,
|
|
2141
|
+
functionName: "getUlnConfig",
|
|
2142
|
+
args: [oapp, dst.lzEid]
|
|
2143
|
+
});
|
|
2144
|
+
return {
|
|
2145
|
+
confirmations: Number(cfg.confirmations),
|
|
2146
|
+
requiredDVNCount: Number(cfg.requiredDVNCount),
|
|
2147
|
+
optionalDVNCount: Number(cfg.optionalDVNCount)
|
|
2148
|
+
};
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
/** Median delivery time of recently delivered messages on this pathway, in seconds. */
|
|
2152
|
+
async observedBridgeSeconds(src, dst) {
|
|
2153
|
+
const pathwayId = `${src.lzEid}-${dst.lzEid}-${src.oftAdapter.toLowerCase()}-${dst.oftAdapter.toLowerCase()}`;
|
|
2154
|
+
return cached(`observed:${pathwayId}`, CACHE_TTL_MS, async () => {
|
|
2155
|
+
const { data } = await scanFetch(`/messages/pathway/${pathwayId}?limit=50`);
|
|
2156
|
+
const durations = (data ?? []).filter((m) => m.status?.name === "DELIVERED").map((m) => (m.destination?.tx?.blockTimestamp ?? 0) - (m.source?.tx?.blockTimestamp ?? 0)).filter((d) => d > 0);
|
|
2157
|
+
return durations.length >= 3 ? Math.round(median(durations)) : void 0;
|
|
2158
|
+
});
|
|
2159
|
+
}
|
|
2160
|
+
validateBridgeParams(params, method) {
|
|
2161
|
+
if (!isAddress4(params.recipient)) {
|
|
2162
|
+
throw new StableValidationError(
|
|
2163
|
+
"recipient",
|
|
2164
|
+
params.recipient,
|
|
2165
|
+
`${method}: invalid recipient address "${params.recipient}"`
|
|
2166
|
+
);
|
|
2167
|
+
}
|
|
2168
|
+
if (!Number.isFinite(params.amount) || params.amount <= 0) {
|
|
2169
|
+
throw new StableValidationError(
|
|
2170
|
+
"amount",
|
|
2171
|
+
params.amount,
|
|
2172
|
+
`${method}: amount must be a finite positive number`
|
|
2173
|
+
);
|
|
2174
|
+
}
|
|
2175
|
+
if (params.fromChain === params.toChain) {
|
|
2176
|
+
throw new StableValidationError(
|
|
2177
|
+
"toChain",
|
|
2178
|
+
params.toChain,
|
|
2179
|
+
`${method}: fromChain and toChain must differ`
|
|
2180
|
+
);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
resolveChains(fromChain, toChain, fromToken, toToken) {
|
|
2184
|
+
const src = BRIDGE_CHAIN_CONFIGS[fromChain];
|
|
2185
|
+
const dst = BRIDGE_CHAIN_CONFIGS[toChain];
|
|
2186
|
+
if (!src) throw new StableValidationError("fromChain", fromChain, `Unsupported source chain: "${fromChain}"`);
|
|
2187
|
+
if (!dst) throw new StableValidationError("toChain", toChain, `Unsupported destination chain: "${toChain}"`);
|
|
2188
|
+
if (!src.oftAdapter) {
|
|
2189
|
+
throw new StableValidationError("fromChain", fromChain, `No OFT adapter configured for "${fromChain}"`);
|
|
2190
|
+
}
|
|
2191
|
+
if (fromToken.toLowerCase() !== src.usdt.toLowerCase()) {
|
|
2192
|
+
throw new StableValidationError(
|
|
2193
|
+
"fromToken",
|
|
2194
|
+
fromToken,
|
|
2195
|
+
`USDT0 bridge only moves USDT0 \u2014 fromToken must be ${src.usdt} on "${fromChain}", got "${fromToken}". Use route "lifi" to bridge other tokens.`
|
|
2196
|
+
);
|
|
2197
|
+
}
|
|
2198
|
+
if (toToken.toLowerCase() !== dst.usdt.toLowerCase()) {
|
|
2199
|
+
throw new StableValidationError(
|
|
2200
|
+
"toToken",
|
|
2201
|
+
toToken,
|
|
2202
|
+
`USDT0 bridge only moves USDT0 \u2014 toToken must be ${dst.usdt} on "${toChain}", got "${toToken}". Use route "lifi" to bridge other tokens.`
|
|
2203
|
+
);
|
|
2204
|
+
}
|
|
2205
|
+
return { src, dst };
|
|
2206
|
+
}
|
|
2207
|
+
buildSendParams(dst, amountLD, recipient) {
|
|
2208
|
+
return {
|
|
2209
|
+
dstEid: dst.lzEid,
|
|
2210
|
+
to: padHex(recipient, { dir: "left", size: 32 }),
|
|
2211
|
+
amountLD,
|
|
2212
|
+
minAmountLD: amountLD,
|
|
2213
|
+
extraOptions: buildLzOptions(),
|
|
2214
|
+
composeMsg: "0x",
|
|
2215
|
+
oftCmd: "0x"
|
|
2216
|
+
};
|
|
2217
|
+
}
|
|
2218
|
+
};
|
|
2219
|
+
|
|
1726
2220
|
// src/stable.ts
|
|
2221
|
+
function isUsdt0Route(fromChain, toChain, fromToken, toToken) {
|
|
2222
|
+
const src = BRIDGE_CHAIN_CONFIGS[fromChain];
|
|
2223
|
+
const dst = BRIDGE_CHAIN_CONFIGS[toChain];
|
|
2224
|
+
return !!src && !!dst && !!src.oftAdapter && src.lzOutbound !== false && src.usdt.toLowerCase() === fromToken.toLowerCase() && dst.usdt.toLowerCase() === toToken.toLowerCase();
|
|
2225
|
+
}
|
|
2226
|
+
function selectBridge(params) {
|
|
2227
|
+
const route = params.route ?? "auto";
|
|
2228
|
+
if (route === "usdt0") return "usdt0";
|
|
2229
|
+
if (route === "lifi") return "lifi";
|
|
2230
|
+
return isUsdt0Route(
|
|
2231
|
+
params.fromChain,
|
|
2232
|
+
params.toChain,
|
|
2233
|
+
params.fromToken,
|
|
2234
|
+
params.toToken
|
|
2235
|
+
) ? "usdt0" : "lifi";
|
|
2236
|
+
}
|
|
1727
2237
|
function validateTransferParams({
|
|
1728
2238
|
to,
|
|
1729
2239
|
amount,
|
|
1730
2240
|
token,
|
|
1731
2241
|
tokenDecimals
|
|
1732
2242
|
}) {
|
|
1733
|
-
if (!
|
|
2243
|
+
if (!isAddress5(to)) {
|
|
1734
2244
|
throw new StableValidationError(
|
|
1735
2245
|
"to",
|
|
1736
2246
|
to,
|
|
@@ -1744,7 +2254,7 @@ function validateTransferParams({
|
|
|
1744
2254
|
"transfer: amount must be a finite positive number"
|
|
1745
2255
|
);
|
|
1746
2256
|
}
|
|
1747
|
-
if (token !== void 0 && !
|
|
2257
|
+
if (token !== void 0 && !isAddress5(token)) {
|
|
1748
2258
|
throw new StableValidationError(
|
|
1749
2259
|
"token",
|
|
1750
2260
|
token,
|
|
@@ -1764,7 +2274,7 @@ async function resolveTokenDecimals(publicClient, token, tokenDecimals) {
|
|
|
1764
2274
|
try {
|
|
1765
2275
|
return await publicClient.readContract({
|
|
1766
2276
|
address: token,
|
|
1767
|
-
abi:
|
|
2277
|
+
abi: erc20Abi5,
|
|
1768
2278
|
functionName: "decimals"
|
|
1769
2279
|
});
|
|
1770
2280
|
} catch {
|
|
@@ -1791,9 +2301,9 @@ async function executeTokenTransfer(wc, publicClient, token, to, amount, tokenDe
|
|
|
1791
2301
|
);
|
|
1792
2302
|
return wc.writeContract({
|
|
1793
2303
|
address: token,
|
|
1794
|
-
abi:
|
|
2304
|
+
abi: erc20Abi5,
|
|
1795
2305
|
functionName: "transfer",
|
|
1796
|
-
args: [to,
|
|
2306
|
+
args: [to, parseUnits5(String(amount), decimals)],
|
|
1797
2307
|
account: acc,
|
|
1798
2308
|
chain
|
|
1799
2309
|
});
|
|
@@ -1814,6 +2324,7 @@ function createStable({
|
|
|
1814
2324
|
);
|
|
1815
2325
|
const signerConfig = { account, transport, walletClient };
|
|
1816
2326
|
const lifi = new LiFiService({ ...signerConfig, rpc, chainId: chain.id });
|
|
2327
|
+
const lz = new LayerZeroService(signerConfig);
|
|
1817
2328
|
const merkl = new MerklService({ ...signerConfig, rpc, chainId: chain.id, merklApiBase });
|
|
1818
2329
|
const morpho = earnConfig ? new MorphoService({
|
|
1819
2330
|
...signerConfig,
|
|
@@ -1821,6 +2332,12 @@ function createStable({
|
|
|
1821
2332
|
chainId: chain.id,
|
|
1822
2333
|
vault: earnConfig.vault
|
|
1823
2334
|
}) : null;
|
|
2335
|
+
const erc3009Client = walletClient ? walletClient : account ? createWalletClient5({
|
|
2336
|
+
account,
|
|
2337
|
+
chain,
|
|
2338
|
+
transport: transport ?? http6(rpc)
|
|
2339
|
+
}) : createPublicClient6({ chain, transport: http6(rpc) });
|
|
2340
|
+
const authorization = erc3009Actions(erc3009Client);
|
|
1824
2341
|
function requireEarn() {
|
|
1825
2342
|
if (!morpho) {
|
|
1826
2343
|
throw new StableValidationError(
|
|
@@ -1846,10 +2363,10 @@ function createStable({
|
|
|
1846
2363
|
validateTransferParams(params);
|
|
1847
2364
|
const { from, to, amount, token, tokenDecimals } = params;
|
|
1848
2365
|
const acc = walletClient?.account ?? account ?? from;
|
|
1849
|
-
const wc = walletClient ??
|
|
2366
|
+
const wc = walletClient ?? createWalletClient5({
|
|
1850
2367
|
account: acc,
|
|
1851
2368
|
chain,
|
|
1852
|
-
transport: transport ??
|
|
2369
|
+
transport: transport ?? http6(rpc)
|
|
1853
2370
|
});
|
|
1854
2371
|
try {
|
|
1855
2372
|
await wc.switchChain({ id: chain.id });
|
|
@@ -1861,9 +2378,9 @@ function createStable({
|
|
|
1861
2378
|
cause: err
|
|
1862
2379
|
});
|
|
1863
2380
|
}
|
|
1864
|
-
const publicClient =
|
|
2381
|
+
const publicClient = createPublicClient6({
|
|
1865
2382
|
chain,
|
|
1866
|
-
transport:
|
|
2383
|
+
transport: http6(rpc)
|
|
1867
2384
|
});
|
|
1868
2385
|
const hash = token !== void 0 ? await executeTokenTransfer(
|
|
1869
2386
|
wc,
|
|
@@ -1881,7 +2398,7 @@ function createStable({
|
|
|
1881
2398
|
account: acc,
|
|
1882
2399
|
chain,
|
|
1883
2400
|
to,
|
|
1884
|
-
value:
|
|
2401
|
+
value: parseUnits5(String(amount), 18)
|
|
1885
2402
|
})
|
|
1886
2403
|
);
|
|
1887
2404
|
const receipt = await publicClient.waitForTransactionReceipt({ hash });
|
|
@@ -1897,10 +2414,13 @@ function createStable({
|
|
|
1897
2414
|
}
|
|
1898
2415
|
return {
|
|
1899
2416
|
transfer,
|
|
1900
|
-
quoteBridge: (params) => lifi.quoteBridge(params),
|
|
1901
|
-
bridge: (params) => lifi.bridge(params),
|
|
2417
|
+
quoteBridge: (params) => selectBridge(params) === "usdt0" ? lz.quoteBridge(params) : lifi.quoteBridge(params),
|
|
2418
|
+
bridge: (params) => selectBridge(params) === "usdt0" ? lz.bridge(params) : lifi.bridge(params),
|
|
2419
|
+
estimateBridgeTime: (params) => lz.estimateBridgeTime(params),
|
|
2420
|
+
trackBridge: (srcTxHash) => lz.trackBridge(srcTxHash),
|
|
1902
2421
|
quoteSwap: (params) => lifi.quoteSwap(params),
|
|
1903
2422
|
swap: (params) => lifi.swap(params),
|
|
2423
|
+
authorization,
|
|
1904
2424
|
earn: {
|
|
1905
2425
|
deposit: (params) => requireEarn().deposit(params),
|
|
1906
2426
|
bulkDeposit: (items, options) => requireEarn().bulkDeposit(items, options),
|
|
@@ -1936,13 +2456,11 @@ function createStableReader(config) {
|
|
|
1936
2456
|
}
|
|
1937
2457
|
};
|
|
1938
2458
|
}
|
|
1939
|
-
|
|
1940
|
-
// src/constants.ts
|
|
1941
|
-
var STABLE_USDT_ADDRESS = "0x779ded0c9e1022225f8e0630b35a9b54be713736";
|
|
1942
|
-
var STABLE_VAULT_ADDRESS = "0xb7Df8db22A5DBBFA9ebeb94b3910aec6a4f05c08";
|
|
1943
2459
|
export {
|
|
2460
|
+
BRIDGE_CHAIN_CONFIGS,
|
|
1944
2461
|
CHAIN_CONFIGS,
|
|
1945
2462
|
Chain,
|
|
2463
|
+
ERC3009_ABI,
|
|
1946
2464
|
Network,
|
|
1947
2465
|
STABLE_USDT_ADDRESS,
|
|
1948
2466
|
STABLE_VAULT_ADDRESS,
|
|
@@ -1952,6 +2470,17 @@ export {
|
|
|
1952
2470
|
StableQuoteError,
|
|
1953
2471
|
StableTransactionError,
|
|
1954
2472
|
StableValidationError,
|
|
2473
|
+
cancelAuthorization,
|
|
2474
|
+
clearBridgeEstimateCache,
|
|
1955
2475
|
createStable,
|
|
1956
|
-
createStableReader
|
|
2476
|
+
createStableReader,
|
|
2477
|
+
erc3009Actions,
|
|
2478
|
+
getAuthorizationState,
|
|
2479
|
+
getAuthorizationUsage,
|
|
2480
|
+
prepareTransferWithAuthorization,
|
|
2481
|
+
receiveWithAuthorization,
|
|
2482
|
+
signReceiveAuthorization,
|
|
2483
|
+
signTransferAuthorization,
|
|
2484
|
+
transferWithAuthorization,
|
|
2485
|
+
verifyAuthorization
|
|
1957
2486
|
};
|