@stablechain/sdk 1.0.6 → 1.0.8
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 +135 -19
- package/dist/index.cjs +310 -98
- package/dist/index.d.cts +320 -10
- package/dist/index.d.ts +320 -10
- package/dist/index.js +290 -78
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1738,6 +1738,7 @@ function isLiFiQuoteShape(v) {
|
|
|
1738
1738
|
|
|
1739
1739
|
|
|
1740
1740
|
|
|
1741
|
+
|
|
1741
1742
|
var C = CHAIN_CONFIGS;
|
|
1742
1743
|
var XAUT0_DEPLOYMENTS = {
|
|
1743
1744
|
["ethereum" /* Ethereum */]: { address: "0x68749665FF8D2d112Fa859AA293F07A622782F38", decimals: 6, oftAdapter: "0xb9c2321BB7D0Db468f570D10A424d1Cc8EFd696C", approvalRequired: true },
|
|
@@ -1749,15 +1750,21 @@ var XAUT0_DEPLOYMENTS = {
|
|
|
1749
1750
|
["plasma" /* Plasma */]: { address: "0x1B64B9025EEbb9A6239575dF9Ea4b9Ac46D4d193", decimals: 6, oftAdapter: "0x63aB93cBC9d4ecD9c4947b1A38F458147C08E6F7", approvalRequired: false },
|
|
1750
1751
|
["bsc" /* BSC */]: { address: "0x21cAef8A43163Eea865baeE23b9C2E327696A3bf", decimals: 6, oftAdapter: "0x53C3A64c8942288e12813C1F8457Db45980BcfC2", approvalRequired: false }
|
|
1751
1752
|
};
|
|
1752
|
-
|
|
1753
|
+
var USDT0_LOCKBOX_CHAINS = /* @__PURE__ */ new Set(["ethereum" /* Ethereum */, "sepolia" /* Sepolia */]);
|
|
1754
|
+
function bridgeChain(chain, lzEid, blockTimeSec, usdt0Adapter, minDeliverySec) {
|
|
1753
1755
|
const base = C[chain];
|
|
1754
1756
|
const tokens = {};
|
|
1755
1757
|
if (usdt0Adapter) {
|
|
1756
|
-
tokens.usdt0 = {
|
|
1758
|
+
tokens.usdt0 = {
|
|
1759
|
+
address: base.usdt,
|
|
1760
|
+
decimals: base.decimals,
|
|
1761
|
+
oftAdapter: usdt0Adapter,
|
|
1762
|
+
approvalRequired: USDT0_LOCKBOX_CHAINS.has(chain)
|
|
1763
|
+
};
|
|
1757
1764
|
}
|
|
1758
1765
|
const xaut0 = XAUT0_DEPLOYMENTS[chain];
|
|
1759
1766
|
if (xaut0) tokens.xaut0 = xaut0;
|
|
1760
|
-
return { ...base, lzEid, blockTimeSec, tokens, oftAdapter: usdt0Adapter };
|
|
1767
|
+
return { ...base, lzEid, blockTimeSec, minDeliverySec, tokens, oftAdapter: usdt0Adapter };
|
|
1761
1768
|
}
|
|
1762
1769
|
var BRIDGE_CHAIN_CONFIGS = {
|
|
1763
1770
|
// ─── Testnet ───────────────────────────────────────────────────────────────
|
|
@@ -1765,18 +1772,18 @@ var BRIDGE_CHAIN_CONFIGS = {
|
|
|
1765
1772
|
["stable-testnet" /* StableTestnet */]: bridgeChain("stable-testnet" /* StableTestnet */, 40374, 0.7, "0x779Ded0c9e1022225f8E0630b35a9b54bE713736"),
|
|
1766
1773
|
// ─── Mainnet ──────────────────────────────────────────────────────────────
|
|
1767
1774
|
["stable" /* Stable */]: bridgeChain("stable" /* Stable */, 30396, 0.7, "0xedaba024be4d87974d5aB11C6Dd586963CcCB027"),
|
|
1768
|
-
["ethereum" /* Ethereum */]: bridgeChain("ethereum" /* Ethereum */, 30101, 12, "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee"),
|
|
1769
|
-
["arbitrum" /* Arbitrum */]: bridgeChain("arbitrum" /* Arbitrum */, 30110, 0.25, "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92"),
|
|
1775
|
+
["ethereum" /* Ethereum */]: bridgeChain("ethereum" /* Ethereum */, 30101, 12, "0x6C96dE32CEa08842dcc4058c14d3aaAD7Fa41dee", 1170),
|
|
1776
|
+
["arbitrum" /* Arbitrum */]: bridgeChain("arbitrum" /* Arbitrum */, 30110, 0.25, "0x14E4A1B13bf7F943c8ff7C51fb60FA964A298D92", 1350),
|
|
1770
1777
|
["ink" /* Ink */]: bridgeChain("ink" /* Ink */, 30339, 1, "0x1cB6De532588fCA4a21B7209DE7C456AF8434A65"),
|
|
1771
|
-
["bera" /* Bera */]: bridgeChain("bera" /* Bera */, 30362, 2, "0x3Dc96399109df5ceb2C226664A086140bD0379cB"),
|
|
1778
|
+
["bera" /* Bera */]: bridgeChain("bera" /* Bera */, 30362, 2, "0x3Dc96399109df5ceb2C226664A086140bD0379cB", 135),
|
|
1772
1779
|
["megaeth" /* MegaETH */]: bridgeChain("megaeth" /* MegaETH */, 30398, 1, "0x9151434b16b9763660705744891fa906f660ecc5"),
|
|
1773
1780
|
["hyperevm" /* HyperEVM */]: bridgeChain("hyperevm" /* HyperEVM */, 30367, 1, "0x904861a24F30EC96ea7CFC3bE9EA4B476d237e98"),
|
|
1774
|
-
["polygon" /* Polygon */]: bridgeChain("polygon" /* Polygon */, 30109, 1.5, "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13"),
|
|
1781
|
+
["polygon" /* Polygon */]: bridgeChain("polygon" /* Polygon */, 30109, 1.5, "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13", 70),
|
|
1775
1782
|
["plasma" /* Plasma */]: bridgeChain("plasma" /* Plasma */, 30383, 1, "0x02ca37966753bDdDf11216B73B16C1dE756A7CF9"),
|
|
1776
1783
|
["optimism" /* Optimism */]: bridgeChain("optimism" /* Optimism */, 30111, 2, "0xF03b4d9AC1D5d1E7c4cEf54C2A313b9fe051A0aD"),
|
|
1777
1784
|
["unichain" /* Unichain */]: bridgeChain("unichain" /* Unichain */, 30320, 1, "0xc07bE8994D035631c36fb4a89C918CeFB2f03EC3"),
|
|
1778
1785
|
["sei" /* Sei */]: bridgeChain("sei" /* Sei */, 30280, 0.5, "0x56Fe74A2e3b484b921c447357203431a3485CC60"),
|
|
1779
|
-
["flare" /* Flare */]: bridgeChain("flare" /* Flare */, 30295, 1.1, "0x567287d2A9829215a37e3B88843d32f9221E7588"),
|
|
1786
|
+
["flare" /* Flare */]: bridgeChain("flare" /* Flare */, 30295, 1.1, "0x567287d2A9829215a37e3B88843d32f9221E7588", 600),
|
|
1780
1787
|
["xlayer" /* XLayer */]: bridgeChain("xlayer" /* XLayer */, 30274, 1, "0x94BCCa6bdfd6A61817Ab0E960bFedE4984505554"),
|
|
1781
1788
|
["rootstock" /* Rootstock */]: bridgeChain("rootstock" /* Rootstock */, 30333, 31, "0x1a594d5d5d1c426281C1064B07f23F57B2716B61"),
|
|
1782
1789
|
// XAUt0 only — BSC has no USDT0 deployment. Block time measured 2026-08-20.
|
|
@@ -1957,6 +1964,14 @@ function median(values) {
|
|
|
1957
1964
|
const mid = Math.floor(sorted.length / 2);
|
|
1958
1965
|
return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
1959
1966
|
}
|
|
1967
|
+
function resolveDeliverySeconds(formulaSeconds, observedSeconds, minDeliverySec) {
|
|
1968
|
+
const base = _nullishCoalesce(formulaSeconds, () => ( observedSeconds));
|
|
1969
|
+
if (base === void 0) return void 0;
|
|
1970
|
+
if (minDeliverySec !== void 0 && minDeliverySec > base) {
|
|
1971
|
+
return { seconds: minDeliverySec, source: "floor" };
|
|
1972
|
+
}
|
|
1973
|
+
return { seconds: base, source: formulaSeconds !== void 0 ? "formula" : "observed" };
|
|
1974
|
+
}
|
|
1960
1975
|
var WORKER_EXECUTOR = 1;
|
|
1961
1976
|
var OPTION_LZRECEIVE = 1;
|
|
1962
1977
|
var OPTION_NATIVE_DROP = 2;
|
|
@@ -1998,6 +2013,22 @@ function buildLzOptions(gasLimit = 0n, nativeDrop = 0n, dropReceiver) {
|
|
|
1998
2013
|
]);
|
|
1999
2014
|
}
|
|
2000
2015
|
var FALLBACK_SEND_GAS = 400000n;
|
|
2016
|
+
var DEFAULT_FEE_BUFFER_BPS = 500;
|
|
2017
|
+
var MAX_FEE_BUFFER_BPS = 1e4;
|
|
2018
|
+
function padFee(nativeFee, bufferBps) {
|
|
2019
|
+
return nativeFee * BigInt(1e4 + bufferBps) / 10000n;
|
|
2020
|
+
}
|
|
2021
|
+
function resolveFeeBuffer(feeBufferBps, method) {
|
|
2022
|
+
if (feeBufferBps === void 0) return DEFAULT_FEE_BUFFER_BPS;
|
|
2023
|
+
if (!Number.isInteger(feeBufferBps) || feeBufferBps < 0 || feeBufferBps > MAX_FEE_BUFFER_BPS) {
|
|
2024
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2025
|
+
"feeBufferBps",
|
|
2026
|
+
feeBufferBps,
|
|
2027
|
+
`${method}: feeBufferBps must be an integer between 0 and ${MAX_FEE_BUFFER_BPS}`
|
|
2028
|
+
);
|
|
2029
|
+
}
|
|
2030
|
+
return feeBufferBps;
|
|
2031
|
+
}
|
|
2001
2032
|
function usableQuote(quote, amountLD) {
|
|
2002
2033
|
if (!_optionalChain([quote, 'optionalAccess', _41 => _41.oft])) return quote;
|
|
2003
2034
|
return quote.oft.amountSentLD <= amountLD ? quote : void 0;
|
|
@@ -2006,20 +2037,46 @@ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
|
2006
2037
|
var LayerZeroService = class {
|
|
2007
2038
|
constructor(config) {
|
|
2008
2039
|
this.config = config;
|
|
2040
|
+
this.rpcById = new Map(
|
|
2041
|
+
Object.entries(_nullishCoalesce(config.rpcOverrides, () => ( {}))).flatMap(([chain, rpc]) => {
|
|
2042
|
+
const id = _optionalChain([CHAIN_CONFIGS, 'access', _42 => _42[chain], 'optionalAccess', _43 => _43.id]);
|
|
2043
|
+
return id === void 0 || !rpc ? [] : [[id, rpc.replace(/\/$/, "")]];
|
|
2044
|
+
})
|
|
2045
|
+
);
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* The RPC to read and broadcast on for a chain: the caller's override when they
|
|
2049
|
+
* gave one, else the built-in public endpoint. Every bridge read goes through
|
|
2050
|
+
* here — a backend quoting on a loop needs an endpoint it controls.
|
|
2051
|
+
*/
|
|
2052
|
+
rpcFor(cfg) {
|
|
2053
|
+
return _nullishCoalesce(this.rpcById.get(cfg.id), () => ( cfg.rpc));
|
|
2009
2054
|
}
|
|
2010
2055
|
async quoteBridge(params) {
|
|
2011
|
-
|
|
2056
|
+
return this.buildQuote(this.plan(params, "quoteBridge"), params, "quoteBridge");
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* The full quote for a planned send. `quoteBridge` reports one; the unsigned
|
|
2060
|
+
* build needs the same numbers and must not disagree with what a caller was
|
|
2061
|
+
* shown, so both come from here.
|
|
2062
|
+
*
|
|
2063
|
+
* `account` is who the gas simulation runs as — this service's signer when it
|
|
2064
|
+
* has one, and the address a prepared send will be signed by when it does not.
|
|
2065
|
+
*/
|
|
2066
|
+
async buildQuote(plan, params, method, opts = {}) {
|
|
2012
2067
|
const [{ fee, oft }, estimate] = await Promise.all([
|
|
2013
|
-
this.quotePathway(plan,
|
|
2068
|
+
this.quotePathway(plan, method, opts.requireOft),
|
|
2014
2069
|
this.estimateBridgeTime(params).catch(() => void 0)
|
|
2015
2070
|
]);
|
|
2016
|
-
const srcGas = await this.estimateSendGas(plan, fee, oft);
|
|
2071
|
+
const srcGas = await this.estimateSendGas(plan, fee, oft, opts.account);
|
|
2017
2072
|
return {
|
|
2018
2073
|
...fee,
|
|
2074
|
+
// What a send built from this quote will actually carry as its `value`.
|
|
2075
|
+
nativeFeeMax: padFee(fee.nativeFee, plan.feeBufferBps),
|
|
2019
2076
|
oft,
|
|
2020
2077
|
// What the recipient is actually credited: input minus any OFT fee and
|
|
2021
2078
|
// minus dust. Falls back to the input when quoteOFT could not be read.
|
|
2022
|
-
toAmount: _nullishCoalesce(_optionalChain([oft, 'optionalAccess',
|
|
2079
|
+
toAmount: _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _44 => _44.amountReceived]), () => ( params.amount)),
|
|
2023
2080
|
srcGas,
|
|
2024
2081
|
totalCostWei: srcGas ? srcGas.costWei + fee.nativeFee : void 0,
|
|
2025
2082
|
estimate
|
|
@@ -2029,10 +2086,15 @@ var LayerZeroService = class {
|
|
|
2029
2086
|
* The LayerZero messaging fee for a send, plus the OFT's own accounting.
|
|
2030
2087
|
*
|
|
2031
2088
|
* The fee is required — a send cannot be built without it. The OFT accounting is
|
|
2032
|
-
* best-effort: an adapter that does not answer `quoteOFT` costs
|
|
2033
|
-
* breakdown and the exact output amount, not the whole quote.
|
|
2089
|
+
* best-effort for a quote: an adapter that does not answer `quoteOFT` costs a
|
|
2090
|
+
* caller the fee breakdown and the exact output amount, not the whole quote.
|
|
2091
|
+
*
|
|
2092
|
+
* `requireOft` flips that for the paths that go on to build a send. Without the
|
|
2093
|
+
* receipt the only slippage floor left is the full input amount, which reverts
|
|
2094
|
+
* with `SlippageExceeded` the moment a pathway charges a fee — so a send that
|
|
2095
|
+
* cannot read `quoteOFT` is one to refuse loudly rather than assemble blind.
|
|
2034
2096
|
*/
|
|
2035
|
-
async quotePathway(plan, method) {
|
|
2097
|
+
async quotePathway(plan, method, requireOft = false) {
|
|
2036
2098
|
const sendParam = this.buildSendParams(plan, 0n);
|
|
2037
2099
|
const [msgFee, oft] = await Promise.all([
|
|
2038
2100
|
plan.pc.readContract({
|
|
@@ -2047,39 +2109,43 @@ var LayerZeroService = class {
|
|
|
2047
2109
|
cause: err
|
|
2048
2110
|
});
|
|
2049
2111
|
}),
|
|
2050
|
-
this.readOftQuote(plan, sendParam)
|
|
2112
|
+
this.readOftQuote(plan, sendParam).catch((err) => {
|
|
2113
|
+
if (!requireOft) return void 0;
|
|
2114
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableQuoteError)({
|
|
2115
|
+
provider: "layerzero",
|
|
2116
|
+
shortMessage: `${method}: quoteOFT call failed \u2014 the adapter's receipt is what floors the send at what it would actually deliver, and there is no safe default for it`,
|
|
2117
|
+
cause: err
|
|
2118
|
+
});
|
|
2119
|
+
})
|
|
2051
2120
|
]);
|
|
2052
2121
|
const { nativeFee, lzTokenFee } = msgFee;
|
|
2053
2122
|
return { fee: { nativeFee, lzTokenFee }, oft };
|
|
2054
2123
|
}
|
|
2055
2124
|
/**
|
|
2056
2125
|
* The adapter's own view of a send: accepted range, its fees, and what lands on
|
|
2057
|
-
* the far side.
|
|
2126
|
+
* the far side. Throws when the adapter will not answer; `quotePathway` decides
|
|
2127
|
+
* whether that is fatal for the caller it is serving.
|
|
2058
2128
|
*/
|
|
2059
2129
|
async readOftQuote(plan, sendParam) {
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
};
|
|
2080
|
-
} catch (e5) {
|
|
2081
|
-
return void 0;
|
|
2082
|
-
}
|
|
2130
|
+
const [limit, feeDetails, receipt] = await plan.pc.readContract({
|
|
2131
|
+
address: plan.oftAdapter,
|
|
2132
|
+
abi: OFT_ADAPTER_ABI,
|
|
2133
|
+
functionName: "quoteOFT",
|
|
2134
|
+
args: [sendParam]
|
|
2135
|
+
});
|
|
2136
|
+
const decimals = plan.srcToken.decimals;
|
|
2137
|
+
return {
|
|
2138
|
+
amountSentLD: receipt.amountSentLD,
|
|
2139
|
+
amountReceivedLD: receipt.amountReceivedLD,
|
|
2140
|
+
amountReceived: Number(_viem.formatUnits.call(void 0, receipt.amountReceivedLD, decimals)),
|
|
2141
|
+
fees: feeDetails.map((detail) => ({
|
|
2142
|
+
amountLD: detail.feeAmountLD,
|
|
2143
|
+
amount: Number(_viem.formatUnits.call(void 0, detail.feeAmountLD, decimals)),
|
|
2144
|
+
description: detail.description
|
|
2145
|
+
})),
|
|
2146
|
+
minAmountLD: limit.minAmountLD,
|
|
2147
|
+
maxAmountLD: limit.maxAmountLD
|
|
2148
|
+
};
|
|
2083
2149
|
}
|
|
2084
2150
|
/**
|
|
2085
2151
|
* Source-chain cost of the `send` transaction.
|
|
@@ -2089,28 +2155,32 @@ var LayerZeroService = class {
|
|
|
2089
2155
|
* before approving does not have. When the simulation reverts, fall back to a
|
|
2090
2156
|
* measured constant so the caller still has a cost to show, flagged as such.
|
|
2091
2157
|
*/
|
|
2092
|
-
async estimateSendGas(plan, fee, oft) {
|
|
2158
|
+
async estimateSendGas(plan, fee, oft, sender) {
|
|
2093
2159
|
const gasPriceWei = await this.gasPrice(plan);
|
|
2094
2160
|
if (gasPriceWei === void 0) return void 0;
|
|
2095
2161
|
let gas = FALLBACK_SEND_GAS;
|
|
2096
2162
|
let source = "fallback";
|
|
2097
|
-
const account = this.signerAddress();
|
|
2163
|
+
const account = _nullishCoalesce(sender, () => ( this.signerAddress()));
|
|
2098
2164
|
if (account) {
|
|
2165
|
+
const sendFee = {
|
|
2166
|
+
nativeFee: padFee(fee.nativeFee, plan.feeBufferBps),
|
|
2167
|
+
lzTokenFee: fee.lzTokenFee
|
|
2168
|
+
};
|
|
2099
2169
|
try {
|
|
2100
2170
|
gas = await plan.pc.estimateContractGas({
|
|
2101
2171
|
address: plan.oftAdapter,
|
|
2102
2172
|
abi: OFT_ADAPTER_ABI,
|
|
2103
2173
|
functionName: "send",
|
|
2104
2174
|
args: [
|
|
2105
|
-
this.buildSendParams(plan, _nullishCoalesce(_optionalChain([oft, 'optionalAccess',
|
|
2106
|
-
|
|
2175
|
+
this.buildSendParams(plan, _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _45 => _45.amountReceivedLD]), () => ( plan.amountLD))),
|
|
2176
|
+
sendFee,
|
|
2107
2177
|
account
|
|
2108
2178
|
],
|
|
2109
2179
|
account,
|
|
2110
|
-
value:
|
|
2180
|
+
value: sendFee.nativeFee
|
|
2111
2181
|
});
|
|
2112
2182
|
source = "simulated";
|
|
2113
|
-
} catch (
|
|
2183
|
+
} catch (e5) {
|
|
2114
2184
|
}
|
|
2115
2185
|
}
|
|
2116
2186
|
return { gas, gasPriceWei, costWei: gas * gasPriceWei, source };
|
|
@@ -2121,41 +2191,58 @@ var LayerZeroService = class {
|
|
|
2121
2191
|
const fees = await plan.pc.estimateFeesPerGas();
|
|
2122
2192
|
const price = _nullishCoalesce(fees.maxFeePerGas, () => ( fees.gasPrice));
|
|
2123
2193
|
if (price !== void 0) return price;
|
|
2124
|
-
} catch (
|
|
2194
|
+
} catch (e6) {
|
|
2125
2195
|
}
|
|
2126
2196
|
try {
|
|
2127
2197
|
return await plan.pc.getGasPrice();
|
|
2128
|
-
} catch (
|
|
2198
|
+
} catch (e7) {
|
|
2129
2199
|
return void 0;
|
|
2130
2200
|
}
|
|
2131
2201
|
}
|
|
2132
2202
|
/**
|
|
2133
|
-
*
|
|
2134
|
-
*
|
|
2203
|
+
* The `approve` amounts to send, in order, before `send` can pull `amountLD` —
|
|
2204
|
+
* empty when the adapter needs no allowance or the existing one already covers
|
|
2205
|
+
* the send.
|
|
2206
|
+
*
|
|
2207
|
+
* A short but non-zero allowance takes two approvals, not one. Legacy USDT on
|
|
2208
|
+
* Ethereum — the only token a lockbox pathway ever approves — refuses to
|
|
2209
|
+
* overwrite a non-zero allowance with another non-zero value:
|
|
2210
|
+
*
|
|
2211
|
+
* require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)))
|
|
2212
|
+
*
|
|
2213
|
+
* so a holder who once approved 5 USDT and now bridges 10 gets a reverted
|
|
2214
|
+
* approve and pays the gas for nothing. Zeroing first is harmless on every
|
|
2215
|
+
* other ERC-20, so it is unconditional rather than sniffed per token.
|
|
2135
2216
|
*/
|
|
2136
|
-
async
|
|
2137
|
-
|
|
2138
|
-
const allowance = await pc.readContract({
|
|
2139
|
-
address: srcToken.address,
|
|
2217
|
+
async approvalPlan(plan, owner, amountLD) {
|
|
2218
|
+
if (plan.srcToken.approvalRequired === false) return [];
|
|
2219
|
+
const allowance = await plan.pc.readContract({
|
|
2220
|
+
address: plan.srcToken.address,
|
|
2140
2221
|
abi: _viem.erc20Abi,
|
|
2141
2222
|
functionName: "allowance",
|
|
2142
|
-
args: [owner, oftAdapter]
|
|
2223
|
+
args: [owner, plan.oftAdapter]
|
|
2143
2224
|
});
|
|
2144
|
-
if (allowance >= amountLD) return;
|
|
2225
|
+
if (allowance >= amountLD) return [];
|
|
2226
|
+
return allowance > 0n ? [0n, amountLD] : [amountLD];
|
|
2227
|
+
}
|
|
2228
|
+
/** Send one `approve` and wait for it to land. */
|
|
2229
|
+
async sendApprove(plan, wc, value) {
|
|
2230
|
+
const { src, asset, srcToken, oftAdapter, pc, chain: srcChain } = plan;
|
|
2231
|
+
const what = value === 0n ? "allowance reset" : "approve";
|
|
2145
2232
|
let approveHash;
|
|
2146
2233
|
try {
|
|
2147
2234
|
approveHash = await wc.writeContract({
|
|
2148
2235
|
address: srcToken.address,
|
|
2149
2236
|
abi: _viem.erc20Abi,
|
|
2150
2237
|
functionName: "approve",
|
|
2151
|
-
args: [oftAdapter,
|
|
2238
|
+
args: [oftAdapter, value],
|
|
2152
2239
|
account: wc.account,
|
|
2153
2240
|
chain: srcChain
|
|
2154
2241
|
});
|
|
2155
2242
|
} catch (err) {
|
|
2156
2243
|
throw new (0, _chunkQQ26UI3Fcjs.StableTransactionError)({
|
|
2157
2244
|
phase: "approve",
|
|
2158
|
-
shortMessage: `bridge: ${asset}
|
|
2245
|
+
shortMessage: `bridge: ${asset} ${what} failed`,
|
|
2159
2246
|
chainId: src.id,
|
|
2160
2247
|
cause: err
|
|
2161
2248
|
});
|
|
@@ -2164,7 +2251,7 @@ var LayerZeroService = class {
|
|
|
2164
2251
|
if (approveReceipt.status === "reverted") {
|
|
2165
2252
|
throw new (0, _chunkQQ26UI3Fcjs.StableTransactionError)({
|
|
2166
2253
|
phase: "approve",
|
|
2167
|
-
shortMessage: `bridge: ${asset}
|
|
2254
|
+
shortMessage: `bridge: ${asset} ${what} reverted on-chain`,
|
|
2168
2255
|
txHash: approveReceipt.transactionHash,
|
|
2169
2256
|
chainId: src.id
|
|
2170
2257
|
});
|
|
@@ -2180,11 +2267,18 @@ var LayerZeroService = class {
|
|
|
2180
2267
|
);
|
|
2181
2268
|
}
|
|
2182
2269
|
const plan = this.plan({ ...params, recipient: _nullishCoalesce(params.recipient, () => ( from)) }, "bridge");
|
|
2183
|
-
const { src,
|
|
2270
|
+
const { src, oftAdapter, amountLD, chain: srcChain } = plan;
|
|
2271
|
+
const refundAddress = this.resolveRefundAddress(params.refundAddress, from, "bridge");
|
|
2184
2272
|
const wc = _nullishCoalesce(this.config.walletClient, () => ( _viem.createWalletClient.call(void 0, {
|
|
2185
2273
|
account: this.config.account,
|
|
2186
2274
|
chain: srcChain,
|
|
2187
|
-
|
|
2275
|
+
// `config.transport` is the caller's *Stable-chain* transport. A browser
|
|
2276
|
+
// wallet transport is chain-agnostic — the wallet holds the keys and picks
|
|
2277
|
+
// the network — but an HTTP one is a broadcast channel bound to a single
|
|
2278
|
+
// chain, and broadcasting an Ethereum send to the Stable RPC fails. With a
|
|
2279
|
+
// local account we sign here and only need somewhere to broadcast, so the
|
|
2280
|
+
// source chain's own endpoint is always the right answer.
|
|
2281
|
+
transport: this.config.account ? _viem.http.call(void 0, plan.rpc) : _nullishCoalesce(this.config.transport, () => ( _viem.http.call(void 0, plan.rpc)))
|
|
2188
2282
|
})));
|
|
2189
2283
|
try {
|
|
2190
2284
|
await wc.switchChain({ id: src.id });
|
|
@@ -2197,22 +2291,23 @@ var LayerZeroService = class {
|
|
|
2197
2291
|
});
|
|
2198
2292
|
}
|
|
2199
2293
|
const quote = usableQuote(params.quote, amountLD);
|
|
2200
|
-
const { nativeFee, lzTokenFee, oft } = _optionalChain([quote, 'optionalAccess',
|
|
2201
|
-
const sendParams = this.buildSendParams(plan, _nullishCoalesce(_optionalChain([oft, 'optionalAccess',
|
|
2202
|
-
|
|
2203
|
-
|
|
2294
|
+
const { nativeFee, lzTokenFee, oft } = _optionalChain([quote, 'optionalAccess', _46 => _46.nativeFee]) !== void 0 && _optionalChain([quote, 'optionalAccess', _47 => _47.lzTokenFee]) !== void 0 ? { nativeFee: quote.nativeFee, lzTokenFee: quote.lzTokenFee, oft: quote.oft } : await this.quotePathway(plan, "bridge", true).then((r) => ({ ...r.fee, oft: r.oft }));
|
|
2295
|
+
const sendParams = this.buildSendParams(plan, _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _48 => _48.amountReceivedLD]), () => ( amountLD)));
|
|
2296
|
+
const sendFee = padFee(nativeFee, plan.feeBufferBps);
|
|
2297
|
+
for (const value of await this.approvalPlan(plan, from, amountLD)) {
|
|
2298
|
+
await this.sendApprove(plan, wc, value);
|
|
2204
2299
|
}
|
|
2205
2300
|
try {
|
|
2206
2301
|
const hash = await wc.writeContract({
|
|
2207
2302
|
address: oftAdapter,
|
|
2208
2303
|
abi: OFT_ADAPTER_ABI,
|
|
2209
2304
|
functionName: "send",
|
|
2210
|
-
args: [sendParams, { nativeFee, lzTokenFee },
|
|
2211
|
-
value:
|
|
2305
|
+
args: [sendParams, { nativeFee: sendFee, lzTokenFee }, refundAddress],
|
|
2306
|
+
value: sendFee,
|
|
2212
2307
|
account: wc.account,
|
|
2213
2308
|
chain: srcChain
|
|
2214
2309
|
});
|
|
2215
|
-
return { txHash: hash, toAmount: _nullishCoalesce(_optionalChain([oft, 'optionalAccess',
|
|
2310
|
+
return { txHash: hash, toAmount: _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _49 => _49.amountReceived]), () => ( params.amount)) };
|
|
2216
2311
|
} catch (err) {
|
|
2217
2312
|
throw new (0, _chunkQQ26UI3Fcjs.StableTransactionError)({
|
|
2218
2313
|
phase: "send",
|
|
@@ -2222,19 +2317,96 @@ var LayerZeroService = class {
|
|
|
2222
2317
|
});
|
|
2223
2318
|
}
|
|
2224
2319
|
}
|
|
2320
|
+
/**
|
|
2321
|
+
* Everything needed to send a bridge, without signing or sending any of it: the
|
|
2322
|
+
* ordered transactions, the quote they were built from, and the `SendParam` the
|
|
2323
|
+
* send step encodes, decoded.
|
|
2324
|
+
*
|
|
2325
|
+
* This is the split-responsibility shape — a backend quotes, builds and checks
|
|
2326
|
+
* while the holder's wallet only signs — and the only way to inspect a bridge
|
|
2327
|
+
* before it exists. Send `steps` in order from `from`, each one confirmed before
|
|
2328
|
+
* the next: an allowance reset and an approve where the lockbox pathway needs
|
|
2329
|
+
* them, then the OFT `send` carrying its fee as `value`.
|
|
2330
|
+
*
|
|
2331
|
+
* Refuses to build when the adapter will not answer `quoteOFT`: the receipt is
|
|
2332
|
+
* what floors the send at what it would actually deliver, and guessing the floor
|
|
2333
|
+
* is how a send reverts with `SlippageExceeded` after the gas is spent.
|
|
2334
|
+
*/
|
|
2335
|
+
async prepareBridgeCalldata(params) {
|
|
2336
|
+
const method = "prepareBridgeCalldata";
|
|
2337
|
+
const from = params.from;
|
|
2338
|
+
if (!_viem.isAddress.call(void 0, from)) {
|
|
2339
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2340
|
+
"from",
|
|
2341
|
+
params.from,
|
|
2342
|
+
`${method}: invalid from address "${params.from}" \u2014 the address that will sign these transactions`
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
const refundAddress = this.resolveRefundAddress(params.refundAddress, from, method);
|
|
2346
|
+
const plan = this.plan({ ...params, recipient: _nullishCoalesce(params.recipient, () => ( from)) }, method);
|
|
2347
|
+
const supplied = usableQuote(params.quote, plan.amountLD);
|
|
2348
|
+
const quote = _optionalChain([supplied, 'optionalAccess', _50 => _50.oft]) && supplied.nativeFee !== void 0 && supplied.lzTokenFee !== void 0 ? supplied : await this.buildQuote(plan, params, method, { account: from, requireOft: true });
|
|
2349
|
+
const oft = quote.oft;
|
|
2350
|
+
const nativeFee = padFee(quote.nativeFee, plan.feeBufferBps);
|
|
2351
|
+
const lzTokenFee = quote.lzTokenFee;
|
|
2352
|
+
const sendParam = this.buildSendParams(plan, oft.amountReceivedLD);
|
|
2353
|
+
const steps = (await this.approvalPlan(plan, from, plan.amountLD)).map((value) => ({
|
|
2354
|
+
chainId: plan.src.id,
|
|
2355
|
+
to: plan.srcToken.address,
|
|
2356
|
+
data: _viem.encodeFunctionData.call(void 0, {
|
|
2357
|
+
abi: _viem.erc20Abi,
|
|
2358
|
+
functionName: "approve",
|
|
2359
|
+
args: [plan.oftAdapter, value]
|
|
2360
|
+
}),
|
|
2361
|
+
value: 0n
|
|
2362
|
+
}));
|
|
2363
|
+
steps.push({
|
|
2364
|
+
chainId: plan.src.id,
|
|
2365
|
+
to: plan.oftAdapter,
|
|
2366
|
+
data: _viem.encodeFunctionData.call(void 0, {
|
|
2367
|
+
abi: OFT_ADAPTER_ABI,
|
|
2368
|
+
functionName: "send",
|
|
2369
|
+
args: [sendParam, { nativeFee, lzTokenFee }, refundAddress]
|
|
2370
|
+
}),
|
|
2371
|
+
value: nativeFee
|
|
2372
|
+
});
|
|
2373
|
+
return {
|
|
2374
|
+
steps,
|
|
2375
|
+
chainId: plan.src.id,
|
|
2376
|
+
asset: plan.asset,
|
|
2377
|
+
quote,
|
|
2378
|
+
send: {
|
|
2379
|
+
dstEid: sendParam.dstEid,
|
|
2380
|
+
recipient: plan.recipient,
|
|
2381
|
+
to: sendParam.to,
|
|
2382
|
+
amountLD: sendParam.amountLD,
|
|
2383
|
+
minAmountLD: sendParam.minAmountLD,
|
|
2384
|
+
extraOptions: sendParam.extraOptions,
|
|
2385
|
+
nativeFee,
|
|
2386
|
+
lzTokenFee,
|
|
2387
|
+
refundAddress
|
|
2388
|
+
}
|
|
2389
|
+
};
|
|
2390
|
+
}
|
|
2225
2391
|
/**
|
|
2226
2392
|
* Estimate how long a USDT0 bridge will take, end to end.
|
|
2227
2393
|
*
|
|
2228
|
-
*
|
|
2229
|
-
*
|
|
2230
|
-
*
|
|
2231
|
-
*
|
|
2232
|
-
*
|
|
2394
|
+
* The number comes from the pathway's live ULN config:
|
|
2395
|
+
* `srcBlockTime × confirmations + dstBlockTime × (2 + dvnCount)`, floored at the
|
|
2396
|
+
* source chain's {@link BridgeChainConfig.minDeliverySec} where the confirmation
|
|
2397
|
+
* count is not the whole wait. This is what the DVNs are actually bound by, so it
|
|
2398
|
+
* tracks a config change the moment it lands — and on every pathway that is purely
|
|
2399
|
+
* confirmation-bound it agrees with both usdt0.to's own estimate and the delivery
|
|
2400
|
+
* times Scan reports to well under a percent.
|
|
2233
2401
|
*
|
|
2234
|
-
*
|
|
2235
|
-
*
|
|
2236
|
-
*
|
|
2237
|
-
*
|
|
2402
|
+
* The observed median of recent deliveries on this exact pathway is fetched too
|
|
2403
|
+
* and reported as {@link BridgeTimeEstimate.observedSeconds}, but it no longer
|
|
2404
|
+
* drives `seconds`. History lags the config: after Optimism→Stable was raised to
|
|
2405
|
+
* 1000 confirmations, a 50-message window still reaching back 261 days put the
|
|
2406
|
+
* median at ~15min against a real ~33min, and pathways quiet for months (Unichain,
|
|
2407
|
+
* XAUt0 from Arbitrum) were answering from configs that no longer exist. It stays
|
|
2408
|
+
* the fallback for the case the formula cannot be computed at all — an RPC that
|
|
2409
|
+
* will not serve the ULN read.
|
|
2238
2410
|
*/
|
|
2239
2411
|
async estimateBridgeTime({
|
|
2240
2412
|
fromChain,
|
|
@@ -2244,8 +2416,8 @@ var LayerZeroService = class {
|
|
|
2244
2416
|
}) {
|
|
2245
2417
|
const src = BRIDGE_CHAIN_CONFIGS[fromChain];
|
|
2246
2418
|
const dst = BRIDGE_CHAIN_CONFIGS[toChain];
|
|
2247
|
-
const from = _nullishCoalesce(fromToken, () => ( _optionalChain([src, 'optionalAccess',
|
|
2248
|
-
const to = _nullishCoalesce(toToken, () => ( _optionalChain([dst, 'optionalAccess',
|
|
2419
|
+
const from = _nullishCoalesce(fromToken, () => ( _optionalChain([src, 'optionalAccess', _51 => _51.tokens, 'access', _52 => _52.usdt0, 'optionalAccess', _53 => _53.address])));
|
|
2420
|
+
const to = _nullishCoalesce(toToken, () => ( _optionalChain([dst, 'optionalAccess', _54 => _54.tokens, 'access', _55 => _55.usdt0, 'optionalAccess', _56 => _56.address])));
|
|
2249
2421
|
if (!(src && from)) {
|
|
2250
2422
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)("fromChain", fromChain, `estimateBridgeTime: no OFT adapter for "${fromChain}"`);
|
|
2251
2423
|
}
|
|
@@ -2265,19 +2437,18 @@ var LayerZeroService = class {
|
|
|
2265
2437
|
);
|
|
2266
2438
|
formulaSeconds = Number.isFinite(computed) ? computed : void 0;
|
|
2267
2439
|
}
|
|
2268
|
-
const
|
|
2269
|
-
if (
|
|
2440
|
+
const resolved = resolveDeliverySeconds(formulaSeconds, observedSeconds, src.minDeliverySec);
|
|
2441
|
+
if (!resolved) {
|
|
2270
2442
|
throw new (0, _chunkQQ26UI3Fcjs.StableQuoteError)({
|
|
2271
2443
|
provider: "layerzero",
|
|
2272
2444
|
shortMessage: `estimateBridgeTime: no pathway data for ${fromChain}\u2192${toChain}`
|
|
2273
2445
|
});
|
|
2274
2446
|
}
|
|
2275
2447
|
return {
|
|
2276
|
-
|
|
2277
|
-
source: observedSeconds !== void 0 ? "observed" : "formula",
|
|
2448
|
+
...resolved,
|
|
2278
2449
|
observedSeconds,
|
|
2279
2450
|
formulaSeconds,
|
|
2280
|
-
confirmations: Number.isFinite(_optionalChain([uln, 'optionalAccess',
|
|
2451
|
+
confirmations: Number.isFinite(_optionalChain([uln, 'optionalAccess', _57 => _57.confirmations])) ? _optionalChain([uln, 'optionalAccess', _58 => _58.confirmations]) : void 0,
|
|
2281
2452
|
dvnCount: Number.isFinite(dvnCount) ? dvnCount : void 0
|
|
2282
2453
|
};
|
|
2283
2454
|
}
|
|
@@ -2290,7 +2461,7 @@ var LayerZeroService = class {
|
|
|
2290
2461
|
const scanUrl = `${LZ_SCAN_UI}/tx/${srcTxHash}`;
|
|
2291
2462
|
let message;
|
|
2292
2463
|
try {
|
|
2293
|
-
message = await _asyncOptionalChain([(await scanFetch(`/messages/tx/${srcTxHash}`)), 'optionalAccess', async
|
|
2464
|
+
message = await _asyncOptionalChain([(await scanFetch(`/messages/tx/${srcTxHash}`)), 'optionalAccess', async _59 => _59.data, 'optionalAccess', async _60 => _60[0]]);
|
|
2294
2465
|
} catch (err) {
|
|
2295
2466
|
if (err instanceof ScanHttpError && err.status === 404) {
|
|
2296
2467
|
return { state: "pending", srcTxHash, scanUrl };
|
|
@@ -2302,15 +2473,15 @@ var LayerZeroService = class {
|
|
|
2302
2473
|
});
|
|
2303
2474
|
}
|
|
2304
2475
|
if (!message) return { state: "pending", srcTxHash, scanUrl };
|
|
2305
|
-
const raw = _nullishCoalesce(_optionalChain([message, 'access',
|
|
2306
|
-
const sentAt = _optionalChain([message, 'access',
|
|
2476
|
+
const raw = _nullishCoalesce(_optionalChain([message, 'access', _61 => _61.status, 'optionalAccess', _62 => _62.name]), () => ( ""));
|
|
2477
|
+
const sentAt = _optionalChain([message, 'access', _63 => _63.source, 'optionalAccess', _64 => _64.tx, 'optionalAccess', _65 => _65.blockTimestamp]);
|
|
2307
2478
|
return {
|
|
2308
2479
|
// Everything terminal that is not DELIVERED means the tokens will not land
|
|
2309
2480
|
// on their own; `raw` carries which of those it was.
|
|
2310
2481
|
state: raw === "DELIVERED" ? "delivered" : TERMINAL_FAILURE_STATUSES.has(raw) ? "failed" : "inflight",
|
|
2311
2482
|
raw,
|
|
2312
2483
|
srcTxHash,
|
|
2313
|
-
dstTxHash: _optionalChain([message, 'access',
|
|
2484
|
+
dstTxHash: _optionalChain([message, 'access', _66 => _66.destination, 'optionalAccess', _67 => _67.tx, 'optionalAccess', _68 => _68.txHash]),
|
|
2314
2485
|
elapsedSeconds: sentAt ? Math.max(0, Math.floor(Date.now() / 1e3) - sentAt) : void 0,
|
|
2315
2486
|
scanUrl
|
|
2316
2487
|
};
|
|
@@ -2318,7 +2489,8 @@ var LayerZeroService = class {
|
|
|
2318
2489
|
/** Effective ULN config the DVNs enforce for this pathway, read from the source chain. */
|
|
2319
2490
|
async getUlnConfig(src, dst, oapp) {
|
|
2320
2491
|
return cached(`uln:${src.lzEid}-${dst.lzEid}-${oapp.toLowerCase()}`, CACHE_TTL_MS, async () => {
|
|
2321
|
-
const
|
|
2492
|
+
const rpc = this.rpcFor(src);
|
|
2493
|
+
const pc = _viem.createPublicClient.call(void 0, { chain: makeChain(src.id, rpc), transport: _viem.http.call(void 0, rpc) });
|
|
2322
2494
|
const endpoint = await pc.readContract({ address: oapp, abi: OAPP_ABI, functionName: "endpoint" });
|
|
2323
2495
|
const sendLib = await pc.readContract({
|
|
2324
2496
|
address: endpoint,
|
|
@@ -2344,7 +2516,7 @@ var LayerZeroService = class {
|
|
|
2344
2516
|
const pathwayId = `${src.lzEid}-${dst.lzEid}-${srcOapp.toLowerCase()}-${dstOapp.toLowerCase()}`;
|
|
2345
2517
|
return cached(`observed:${pathwayId}`, CACHE_TTL_MS, async () => {
|
|
2346
2518
|
const { data } = await scanFetch(`/messages/pathway/${pathwayId}?limit=50`);
|
|
2347
|
-
const durations = (_nullishCoalesce(data, () => ( []))).filter((m) => _optionalChain([m, 'access',
|
|
2519
|
+
const durations = (_nullishCoalesce(data, () => ( []))).filter((m) => _optionalChain([m, 'access', _69 => _69.status, 'optionalAccess', _70 => _70.name]) === "DELIVERED").map((m) => (_nullishCoalesce(_optionalChain([m, 'access', _71 => _71.destination, 'optionalAccess', _72 => _72.tx, 'optionalAccess', _73 => _73.blockTimestamp]), () => ( 0))) - (_nullishCoalesce(_optionalChain([m, 'access', _74 => _74.source, 'optionalAccess', _75 => _75.tx, 'optionalAccess', _76 => _76.blockTimestamp]), () => ( 0)))).filter((d) => d > 0);
|
|
2348
2520
|
return durations.length >= 3 ? Math.round(median(durations)) : void 0;
|
|
2349
2521
|
});
|
|
2350
2522
|
}
|
|
@@ -2424,13 +2596,22 @@ var LayerZeroService = class {
|
|
|
2424
2596
|
`${method}: dstNativeDrop must not be negative`
|
|
2425
2597
|
);
|
|
2426
2598
|
}
|
|
2599
|
+
const feeBufferBps = resolveFeeBuffer(params.feeBufferBps, method);
|
|
2427
2600
|
const { src, dst, asset, srcToken, dstToken } = this.resolveRoute(
|
|
2428
2601
|
fromChain,
|
|
2429
2602
|
toChain,
|
|
2430
2603
|
fromToken,
|
|
2431
2604
|
toToken
|
|
2432
2605
|
);
|
|
2433
|
-
|
|
2606
|
+
if (params.fromDecimals !== void 0 && params.fromDecimals !== srcToken.decimals) {
|
|
2607
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2608
|
+
"fromDecimals",
|
|
2609
|
+
params.fromDecimals,
|
|
2610
|
+
`${method}: ${asset} has ${srcToken.decimals} decimals on "${fromChain}", not ${params.fromDecimals}. The native OFT route parses the amount with the token's own decimals; fromDecimals applies to LI.FI routes only.`
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
const rpc = this.rpcFor(src);
|
|
2614
|
+
const chain = makeChain(src.id, rpc);
|
|
2434
2615
|
return {
|
|
2435
2616
|
src,
|
|
2436
2617
|
dst,
|
|
@@ -2441,13 +2622,31 @@ var LayerZeroService = class {
|
|
|
2441
2622
|
amountLD: _viem.parseUnits.call(void 0, String(amount), srcToken.decimals),
|
|
2442
2623
|
recipient: recipientAddr,
|
|
2443
2624
|
nativeDrop: _nullishCoalesce(dstNativeDrop, () => ( 0n)),
|
|
2625
|
+
rpc,
|
|
2626
|
+
feeBufferBps,
|
|
2444
2627
|
chain,
|
|
2445
|
-
pc: _viem.createPublicClient.call(void 0, { chain, transport: _viem.http.call(void 0,
|
|
2628
|
+
pc: _viem.createPublicClient.call(void 0, { chain, transport: _viem.http.call(void 0, rpc) })
|
|
2446
2629
|
};
|
|
2447
2630
|
}
|
|
2631
|
+
/**
|
|
2632
|
+
* Where `send` returns messaging fee it did not need. Defaults to the sender,
|
|
2633
|
+
* which is what a caller wants unless they are routing refunds somewhere of
|
|
2634
|
+
* their own — a backend paying the fee on a user's behalf, say.
|
|
2635
|
+
*/
|
|
2636
|
+
resolveRefundAddress(refundAddress, sender, method) {
|
|
2637
|
+
if (refundAddress === void 0) return sender;
|
|
2638
|
+
if (!_viem.isAddress.call(void 0, refundAddress)) {
|
|
2639
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2640
|
+
"refundAddress",
|
|
2641
|
+
refundAddress,
|
|
2642
|
+
`${method}: invalid refundAddress "${refundAddress}"`
|
|
2643
|
+
);
|
|
2644
|
+
}
|
|
2645
|
+
return refundAddress;
|
|
2646
|
+
}
|
|
2448
2647
|
/** The address that will sign, or undefined when this service has no signer. */
|
|
2449
2648
|
signerAddress() {
|
|
2450
|
-
return _nullishCoalesce(_optionalChain([this, 'access',
|
|
2649
|
+
return _nullishCoalesce(_optionalChain([this, 'access', _77 => _77.config, 'access', _78 => _78.walletClient, 'optionalAccess', _79 => _79.account, 'optionalAccess', _80 => _80.address]), () => ( _optionalChain([this, 'access', _81 => _81.config, 'access', _82 => _82.account, 'optionalAccess', _83 => _83.address])));
|
|
2451
2650
|
}
|
|
2452
2651
|
/**
|
|
2453
2652
|
* `SendParam` for one call. `minAmountLD` is the caller's slippage floor: 0 when
|
|
@@ -2542,7 +2741,7 @@ async function resolveTokenDecimals(publicClient, token, tokenDecimals) {
|
|
|
2542
2741
|
abi: _viem.erc20Abi,
|
|
2543
2742
|
functionName: "decimals"
|
|
2544
2743
|
});
|
|
2545
|
-
} catch (
|
|
2744
|
+
} catch (e8) {
|
|
2546
2745
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2547
2746
|
"tokenDecimals",
|
|
2548
2747
|
void 0,
|
|
@@ -2576,6 +2775,7 @@ async function executeTokenTransfer(wc, publicClient, token, to, amount, tokenDe
|
|
|
2576
2775
|
function createStable({
|
|
2577
2776
|
network = "mainnet" /* Mainnet */,
|
|
2578
2777
|
rpc: rpcOverride,
|
|
2778
|
+
rpcOverrides,
|
|
2579
2779
|
account,
|
|
2580
2780
|
transport,
|
|
2581
2781
|
walletClient,
|
|
@@ -2589,7 +2789,7 @@ function createStable({
|
|
|
2589
2789
|
);
|
|
2590
2790
|
const signerConfig = { account, transport, walletClient };
|
|
2591
2791
|
const lifi = new LiFiService({ ...signerConfig, rpc, chainId: chain.id });
|
|
2592
|
-
const lz = new LayerZeroService(signerConfig);
|
|
2792
|
+
const lz = new LayerZeroService({ ...signerConfig, rpcOverrides });
|
|
2593
2793
|
const merkl = new MerklService({ ...signerConfig, rpc, chainId: chain.id, merklApiBase });
|
|
2594
2794
|
const morpho = earnConfig ? new MorphoService({
|
|
2595
2795
|
...signerConfig,
|
|
@@ -2614,7 +2814,7 @@ function createStable({
|
|
|
2614
2814
|
return morpho;
|
|
2615
2815
|
}
|
|
2616
2816
|
function requireSignerAddress() {
|
|
2617
|
-
const from = _nullishCoalesce(_optionalChain([walletClient, 'optionalAccess',
|
|
2817
|
+
const from = _nullishCoalesce(_optionalChain([walletClient, 'optionalAccess', _84 => _84.account, 'optionalAccess', _85 => _85.address]), () => ( _optionalChain([account, 'optionalAccess', _86 => _86.address])));
|
|
2618
2818
|
if (!from) {
|
|
2619
2819
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2620
2820
|
"signer",
|
|
@@ -2627,7 +2827,7 @@ function createStable({
|
|
|
2627
2827
|
async function transfer(params) {
|
|
2628
2828
|
validateTransferParams(params);
|
|
2629
2829
|
const { from, to, amount, token, tokenDecimals } = params;
|
|
2630
|
-
const acc = _nullishCoalesce(_nullishCoalesce(_optionalChain([walletClient, 'optionalAccess',
|
|
2830
|
+
const acc = _nullishCoalesce(_nullishCoalesce(_optionalChain([walletClient, 'optionalAccess', _87 => _87.account]), () => ( account)), () => ( from));
|
|
2631
2831
|
const wc = _nullishCoalesce(walletClient, () => ( _viem.createWalletClient.call(void 0, {
|
|
2632
2832
|
account: acc,
|
|
2633
2833
|
chain,
|
|
@@ -2683,6 +2883,16 @@ function createStable({
|
|
|
2683
2883
|
// promise like every other validation error, not a synchronous throw.
|
|
2684
2884
|
quoteBridge: async (params) => selectBridge(params) === "oft" ? lz.quoteBridge(params) : lifi.quoteBridge(params),
|
|
2685
2885
|
bridge: async (params) => selectBridge(params) === "oft" ? lz.bridge(params) : lifi.bridge(params),
|
|
2886
|
+
prepareBridgeCalldata: async (params) => {
|
|
2887
|
+
if (selectBridge(params) !== "oft") {
|
|
2888
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2889
|
+
"route",
|
|
2890
|
+
_nullishCoalesce(params.route, () => ( "auto")),
|
|
2891
|
+
`prepareBridgeCalldata: only the native OFT route can be built unsigned, and ${params.fromChain}\u2192${params.toChain} resolved to LI.FI`
|
|
2892
|
+
);
|
|
2893
|
+
}
|
|
2894
|
+
return lz.prepareBridgeCalldata(params);
|
|
2895
|
+
},
|
|
2686
2896
|
estimateBridgeTime: (params) => lz.estimateBridgeTime(params),
|
|
2687
2897
|
trackBridge: (srcTxHash) => lz.trackBridge(srcTxHash),
|
|
2688
2898
|
quoteSwap: (params) => lifi.quoteSwap(params),
|
|
@@ -2751,4 +2961,6 @@ function createStableReader(config) {
|
|
|
2751
2961
|
|
|
2752
2962
|
|
|
2753
2963
|
|
|
2754
|
-
|
|
2964
|
+
|
|
2965
|
+
|
|
2966
|
+
exports.BRIDGE_CHAIN_CONFIGS = BRIDGE_CHAIN_CONFIGS; exports.CHAIN_CONFIGS = CHAIN_CONFIGS; exports.Chain = Chain; exports.ERC3009_ABI = _chunkQQ26UI3Fcjs.ERC3009_ABI; exports.Network = Network; exports.OFT_ADAPTER_ABI = OFT_ADAPTER_ABI; exports.STABLE_USDT_ADDRESS = _chunkQQ26UI3Fcjs.STABLE_USDT_ADDRESS; exports.STABLE_VAULT_ADDRESS = _chunkQQ26UI3Fcjs.STABLE_VAULT_ADDRESS; exports.StableBulkError = _chunkQQ26UI3Fcjs.StableBulkError; exports.StableError = _chunkQQ26UI3Fcjs.StableError; exports.StableNetworkError = _chunkQQ26UI3Fcjs.StableNetworkError; exports.StableQuoteError = _chunkQQ26UI3Fcjs.StableQuoteError; exports.StableTransactionError = _chunkQQ26UI3Fcjs.StableTransactionError; exports.StableValidationError = _chunkQQ26UI3Fcjs.StableValidationError; exports.bridgeAssetFor = bridgeAssetFor; exports.buildLzOptions = buildLzOptions; exports.cancelAuthorization = _chunkQQ26UI3Fcjs.cancelAuthorization; exports.clearBridgeEstimateCache = clearBridgeEstimateCache; exports.createStable = createStable; exports.createStableReader = createStableReader; exports.erc3009Actions = _chunkQQ26UI3Fcjs.erc3009Actions; exports.getAuthorizationState = _chunkQQ26UI3Fcjs.getAuthorizationState; exports.getAuthorizationUsage = _chunkQQ26UI3Fcjs.getAuthorizationUsage; exports.prepareTransferWithAuthorization = _chunkQQ26UI3Fcjs.prepareTransferWithAuthorization; exports.receiveWithAuthorization = _chunkQQ26UI3Fcjs.receiveWithAuthorization; exports.signReceiveAuthorization = _chunkQQ26UI3Fcjs.signReceiveAuthorization; exports.signTransferAuthorization = _chunkQQ26UI3Fcjs.signTransferAuthorization; exports.transferWithAuthorization = _chunkQQ26UI3Fcjs.transferWithAuthorization; exports.verifyAuthorization = _chunkQQ26UI3Fcjs.verifyAuthorization;
|