@stablechain/sdk 1.0.5 → 1.0.6
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 +129 -8
- package/dist/index.cjs +426 -158
- package/dist/index.d.cts +148 -17
- package/dist/index.d.ts +148 -17
- package/dist/index.js +416 -148
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1737,46 +1737,81 @@ function isLiFiQuoteShape(v) {
|
|
|
1737
1737
|
|
|
1738
1738
|
|
|
1739
1739
|
|
|
1740
|
+
|
|
1740
1741
|
var C = CHAIN_CONFIGS;
|
|
1742
|
+
var XAUT0_DEPLOYMENTS = {
|
|
1743
|
+
["ethereum" /* Ethereum */]: { address: "0x68749665FF8D2d112Fa859AA293F07A622782F38", decimals: 6, oftAdapter: "0xb9c2321BB7D0Db468f570D10A424d1Cc8EFd696C", approvalRequired: true },
|
|
1744
|
+
["stable" /* Stable */]: { address: "0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb", decimals: 6, oftAdapter: "0xD8479f87686ed263D00Ca7505F86327dbeD4171A", approvalRequired: false },
|
|
1745
|
+
["arbitrum" /* Arbitrum */]: { address: "0x40461291347e1eCbb09499F3371D3f17f10d7159", decimals: 6, oftAdapter: "0xf40542a7B66AD7C68C459EE3679635D2fDB6dF39", approvalRequired: false },
|
|
1746
|
+
["ink" /* Ink */]: { address: "0xF50258D3c1dd88946C567920B986A12e65b50dAc", decimals: 6, oftAdapter: "0xA1bE1572B4beef24f812EfDc58bdc41D56a0dAB2", approvalRequired: false },
|
|
1747
|
+
["hyperevm" /* HyperEVM */]: { address: "0xf4D9235269a96aaDaFc9aDAe454a0618eBE37949", decimals: 6, oftAdapter: "0x4E41cfc3F3B19E29E323D2c36F8f202a1e151dAF", approvalRequired: false },
|
|
1748
|
+
["polygon" /* Polygon */]: { address: "0xF1815bd50389c46847f0Bda824eC8da914045D14", decimals: 6, oftAdapter: "0x5421Cf4288d8007D3c43AC4246eaFCe5b049e352", approvalRequired: false },
|
|
1749
|
+
["plasma" /* Plasma */]: { address: "0x1B64B9025EEbb9A6239575dF9Ea4b9Ac46D4d193", decimals: 6, oftAdapter: "0x63aB93cBC9d4ecD9c4947b1A38F458147C08E6F7", approvalRequired: false },
|
|
1750
|
+
["bsc" /* BSC */]: { address: "0x21cAef8A43163Eea865baeE23b9C2E327696A3bf", decimals: 6, oftAdapter: "0x53C3A64c8942288e12813C1F8457Db45980BcfC2", approvalRequired: false }
|
|
1751
|
+
};
|
|
1752
|
+
function bridgeChain(chain, lzEid, blockTimeSec, usdt0Adapter) {
|
|
1753
|
+
const base = C[chain];
|
|
1754
|
+
const tokens = {};
|
|
1755
|
+
if (usdt0Adapter) {
|
|
1756
|
+
tokens.usdt0 = { address: base.usdt, decimals: base.decimals, oftAdapter: usdt0Adapter };
|
|
1757
|
+
}
|
|
1758
|
+
const xaut0 = XAUT0_DEPLOYMENTS[chain];
|
|
1759
|
+
if (xaut0) tokens.xaut0 = xaut0;
|
|
1760
|
+
return { ...base, lzEid, blockTimeSec, tokens, oftAdapter: usdt0Adapter };
|
|
1761
|
+
}
|
|
1741
1762
|
var BRIDGE_CHAIN_CONFIGS = {
|
|
1742
1763
|
// ─── Testnet ───────────────────────────────────────────────────────────────
|
|
1743
|
-
["sepolia" /* Sepolia */]:
|
|
1744
|
-
["stable-testnet" /* StableTestnet */]:
|
|
1764
|
+
["sepolia" /* Sepolia */]: bridgeChain("sepolia" /* Sepolia */, 40161, 12, "0xc099cD946d5efCC35A99D64E808c1430cEf08126"),
|
|
1765
|
+
["stable-testnet" /* StableTestnet */]: bridgeChain("stable-testnet" /* StableTestnet */, 40374, 0.7, "0x779Ded0c9e1022225f8E0630b35a9b54bE713736"),
|
|
1745
1766
|
// ─── Mainnet ──────────────────────────────────────────────────────────────
|
|
1746
|
-
["stable" /* Stable */]:
|
|
1747
|
-
["ethereum" /* Ethereum */]:
|
|
1748
|
-
["arbitrum" /* Arbitrum */]:
|
|
1749
|
-
["ink" /* Ink */]:
|
|
1750
|
-
["bera" /* Bera */]:
|
|
1751
|
-
["megaeth" /* MegaETH */]:
|
|
1752
|
-
["hyperevm" /* HyperEVM */]:
|
|
1753
|
-
["polygon" /* Polygon */]:
|
|
1754
|
-
["plasma" /* Plasma */]:
|
|
1755
|
-
["optimism" /* Optimism */]:
|
|
1756
|
-
["unichain" /* Unichain */]:
|
|
1757
|
-
["sei" /* Sei */]:
|
|
1758
|
-
["flare" /* Flare */]:
|
|
1759
|
-
["xlayer" /* XLayer */]:
|
|
1760
|
-
["rootstock" /* Rootstock */]:
|
|
1767
|
+
["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"),
|
|
1770
|
+
["ink" /* Ink */]: bridgeChain("ink" /* Ink */, 30339, 1, "0x1cB6De532588fCA4a21B7209DE7C456AF8434A65"),
|
|
1771
|
+
["bera" /* Bera */]: bridgeChain("bera" /* Bera */, 30362, 2, "0x3Dc96399109df5ceb2C226664A086140bD0379cB"),
|
|
1772
|
+
["megaeth" /* MegaETH */]: bridgeChain("megaeth" /* MegaETH */, 30398, 1, "0x9151434b16b9763660705744891fa906f660ecc5"),
|
|
1773
|
+
["hyperevm" /* HyperEVM */]: bridgeChain("hyperevm" /* HyperEVM */, 30367, 1, "0x904861a24F30EC96ea7CFC3bE9EA4B476d237e98"),
|
|
1774
|
+
["polygon" /* Polygon */]: bridgeChain("polygon" /* Polygon */, 30109, 1.5, "0x6BA10300f0DC58B7a1e4c0e41f5daBb7D7829e13"),
|
|
1775
|
+
["plasma" /* Plasma */]: bridgeChain("plasma" /* Plasma */, 30383, 1, "0x02ca37966753bDdDf11216B73B16C1dE756A7CF9"),
|
|
1776
|
+
["optimism" /* Optimism */]: bridgeChain("optimism" /* Optimism */, 30111, 2, "0xF03b4d9AC1D5d1E7c4cEf54C2A313b9fe051A0aD"),
|
|
1777
|
+
["unichain" /* Unichain */]: bridgeChain("unichain" /* Unichain */, 30320, 1, "0xc07bE8994D035631c36fb4a89C918CeFB2f03EC3"),
|
|
1778
|
+
["sei" /* Sei */]: bridgeChain("sei" /* Sei */, 30280, 0.5, "0x56Fe74A2e3b484b921c447357203431a3485CC60"),
|
|
1779
|
+
["flare" /* Flare */]: bridgeChain("flare" /* Flare */, 30295, 1.1, "0x567287d2A9829215a37e3B88843d32f9221E7588"),
|
|
1780
|
+
["xlayer" /* XLayer */]: bridgeChain("xlayer" /* XLayer */, 30274, 1, "0x94BCCa6bdfd6A61817Ab0E960bFedE4984505554"),
|
|
1781
|
+
["rootstock" /* Rootstock */]: bridgeChain("rootstock" /* Rootstock */, 30333, 31, "0x1a594d5d5d1c426281C1064B07f23F57B2716B61"),
|
|
1782
|
+
// XAUt0 only — BSC has no USDT0 deployment. Block time measured 2026-08-20.
|
|
1783
|
+
["bsc" /* BSC */]: bridgeChain("bsc" /* BSC */, 30102, 0.45)
|
|
1784
|
+
};
|
|
1785
|
+
function bridgeAssetFor(cfg, token) {
|
|
1786
|
+
const needle = token.toLowerCase();
|
|
1787
|
+
return Object.keys(cfg.tokens).find(
|
|
1788
|
+
(asset) => _optionalChain([cfg, 'access', _36 => _36.tokens, 'access', _37 => _37[asset], 'optionalAccess', _38 => _38.address, 'access', _39 => _39.toLowerCase, 'call', _40 => _40()]) === needle
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
function describeAssets(cfg) {
|
|
1792
|
+
const assets = Object.entries(cfg.tokens);
|
|
1793
|
+
if (assets.length === 0) return "no OFT assets";
|
|
1794
|
+
return assets.map(([asset, token]) => `${asset} (${token.address})`).join(" or ");
|
|
1795
|
+
}
|
|
1796
|
+
var SEND_PARAM_INPUT = {
|
|
1797
|
+
name: "_sendParam",
|
|
1798
|
+
type: "tuple",
|
|
1799
|
+
components: [
|
|
1800
|
+
{ name: "dstEid", type: "uint32" },
|
|
1801
|
+
{ name: "to", type: "bytes32" },
|
|
1802
|
+
{ name: "amountLD", type: "uint256" },
|
|
1803
|
+
{ name: "minAmountLD", type: "uint256" },
|
|
1804
|
+
{ name: "extraOptions", type: "bytes" },
|
|
1805
|
+
{ name: "composeMsg", type: "bytes" },
|
|
1806
|
+
{ name: "oftCmd", type: "bytes" }
|
|
1807
|
+
]
|
|
1761
1808
|
};
|
|
1762
1809
|
var OFT_ADAPTER_ABI = [
|
|
1763
1810
|
{
|
|
1764
1811
|
name: "quoteSend",
|
|
1765
1812
|
type: "function",
|
|
1766
1813
|
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
|
-
},
|
|
1814
|
+
SEND_PARAM_INPUT,
|
|
1780
1815
|
{ name: "_payInLzToken", type: "bool" }
|
|
1781
1816
|
],
|
|
1782
1817
|
outputs: [
|
|
@@ -1792,22 +1827,48 @@ var OFT_ADAPTER_ABI = [
|
|
|
1792
1827
|
stateMutability: "view"
|
|
1793
1828
|
},
|
|
1794
1829
|
{
|
|
1795
|
-
|
|
1830
|
+
// OFT-level accounting, independent of the LayerZero messaging fee: the
|
|
1831
|
+
// pathway's accepted range, any fee the adapter charges itself, and what the
|
|
1832
|
+
// recipient actually ends up credited.
|
|
1833
|
+
name: "quoteOFT",
|
|
1796
1834
|
type: "function",
|
|
1797
1835
|
inputs: [
|
|
1836
|
+
SEND_PARAM_INPUT
|
|
1837
|
+
],
|
|
1838
|
+
outputs: [
|
|
1798
1839
|
{
|
|
1799
|
-
name: "
|
|
1840
|
+
name: "oftLimit",
|
|
1800
1841
|
type: "tuple",
|
|
1801
1842
|
components: [
|
|
1802
|
-
{ name: "dstEid", type: "uint32" },
|
|
1803
|
-
{ name: "to", type: "bytes32" },
|
|
1804
|
-
{ name: "amountLD", type: "uint256" },
|
|
1805
1843
|
{ name: "minAmountLD", type: "uint256" },
|
|
1806
|
-
{ name: "
|
|
1807
|
-
|
|
1808
|
-
|
|
1844
|
+
{ name: "maxAmountLD", type: "uint256" }
|
|
1845
|
+
]
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
name: "oftFeeDetails",
|
|
1849
|
+
type: "tuple[]",
|
|
1850
|
+
components: [
|
|
1851
|
+
// Signed: a negative detail is a credit to the sender, not a charge.
|
|
1852
|
+
{ name: "feeAmountLD", type: "int256" },
|
|
1853
|
+
{ name: "description", type: "string" }
|
|
1809
1854
|
]
|
|
1810
1855
|
},
|
|
1856
|
+
{
|
|
1857
|
+
name: "oftReceipt",
|
|
1858
|
+
type: "tuple",
|
|
1859
|
+
components: [
|
|
1860
|
+
{ name: "amountSentLD", type: "uint256" },
|
|
1861
|
+
{ name: "amountReceivedLD", type: "uint256" }
|
|
1862
|
+
]
|
|
1863
|
+
}
|
|
1864
|
+
],
|
|
1865
|
+
stateMutability: "view"
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
name: "send",
|
|
1869
|
+
type: "function",
|
|
1870
|
+
inputs: [
|
|
1871
|
+
SEND_PARAM_INPUT,
|
|
1811
1872
|
{
|
|
1812
1873
|
name: "_fee",
|
|
1813
1874
|
type: "tuple",
|
|
@@ -1880,7 +1941,7 @@ var ScanHttpError = class extends Error {
|
|
|
1880
1941
|
async function scanFetch(path, timeoutMs = 8e3) {
|
|
1881
1942
|
const res = await fetch(`${LZ_SCAN_API}${path}`, { signal: AbortSignal.timeout(timeoutMs) });
|
|
1882
1943
|
if (!res.ok) throw new ScanHttpError(res.status, path);
|
|
1883
|
-
return res.json();
|
|
1944
|
+
return await res.json();
|
|
1884
1945
|
}
|
|
1885
1946
|
var TERMINAL_FAILURE_STATUSES = /* @__PURE__ */ new Set([
|
|
1886
1947
|
"FAILED",
|
|
@@ -1896,62 +1957,221 @@ function median(values) {
|
|
|
1896
1957
|
const mid = Math.floor(sorted.length / 2);
|
|
1897
1958
|
return sorted.length % 2 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
|
|
1898
1959
|
}
|
|
1899
|
-
|
|
1960
|
+
var WORKER_EXECUTOR = 1;
|
|
1961
|
+
var OPTION_LZRECEIVE = 1;
|
|
1962
|
+
var OPTION_NATIVE_DROP = 2;
|
|
1963
|
+
function lzOption(optionType, payload) {
|
|
1964
|
+
const payloadBytes = (payload.length - 2) / 2;
|
|
1965
|
+
return _viem.concat.call(void 0, [
|
|
1966
|
+
_viem.numberToHex.call(void 0, WORKER_EXECUTOR, { size: 1 }),
|
|
1967
|
+
_viem.numberToHex.call(void 0, 1 + payloadBytes, { size: 2 }),
|
|
1968
|
+
_viem.numberToHex.call(void 0, optionType, { size: 1 }),
|
|
1969
|
+
payload
|
|
1970
|
+
]);
|
|
1971
|
+
}
|
|
1972
|
+
function buildLzOptions(gasLimit = 0n, nativeDrop = 0n, dropReceiver) {
|
|
1973
|
+
const options = [
|
|
1974
|
+
lzOption(OPTION_LZRECEIVE, _viem.numberToHex.call(void 0, gasLimit, { size: 16 }))
|
|
1975
|
+
];
|
|
1976
|
+
if (nativeDrop > 0n) {
|
|
1977
|
+
if (!dropReceiver) {
|
|
1978
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
1979
|
+
"recipient",
|
|
1980
|
+
dropReceiver,
|
|
1981
|
+
"buildLzOptions: a native drop needs a receiver address"
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
options.push(
|
|
1985
|
+
lzOption(
|
|
1986
|
+
OPTION_NATIVE_DROP,
|
|
1987
|
+
_viem.concat.call(void 0, [
|
|
1988
|
+
_viem.numberToHex.call(void 0, nativeDrop, { size: 16 }),
|
|
1989
|
+
_viem.padHex.call(void 0, dropReceiver, { dir: "left", size: 32 })
|
|
1990
|
+
])
|
|
1991
|
+
)
|
|
1992
|
+
);
|
|
1993
|
+
}
|
|
1900
1994
|
return _viem.concat.call(void 0, [
|
|
1901
1995
|
_viem.numberToHex.call(void 0, 3, { size: 2 }),
|
|
1902
1996
|
// TYPE_3 header
|
|
1903
|
-
|
|
1904
|
-
// Executor worker ID
|
|
1905
|
-
_viem.numberToHex.call(void 0, 17, { size: 2 }),
|
|
1906
|
-
// option payload length = 17 bytes
|
|
1907
|
-
_viem.numberToHex.call(void 0, 1, { size: 1 }),
|
|
1908
|
-
// LzReceive option type
|
|
1909
|
-
_viem.numberToHex.call(void 0, gasLimit, { size: 16 })
|
|
1910
|
-
// gas limit as uint128
|
|
1997
|
+
...options
|
|
1911
1998
|
]);
|
|
1912
1999
|
}
|
|
2000
|
+
var FALLBACK_SEND_GAS = 400000n;
|
|
2001
|
+
function usableQuote(quote, amountLD) {
|
|
2002
|
+
if (!_optionalChain([quote, 'optionalAccess', _41 => _41.oft])) return quote;
|
|
2003
|
+
return quote.oft.amountSentLD <= amountLD ? quote : void 0;
|
|
2004
|
+
}
|
|
2005
|
+
var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
1913
2006
|
var LayerZeroService = class {
|
|
1914
2007
|
constructor(config) {
|
|
1915
2008
|
this.config = config;
|
|
1916
2009
|
}
|
|
1917
2010
|
async quoteBridge(params) {
|
|
1918
|
-
const
|
|
1919
|
-
|
|
2011
|
+
const plan = this.plan(params, "quoteBridge");
|
|
2012
|
+
const [{ fee, oft }, estimate] = await Promise.all([
|
|
2013
|
+
this.quotePathway(plan, "quoteBridge"),
|
|
1920
2014
|
this.estimateBridgeTime(params).catch(() => void 0)
|
|
1921
2015
|
]);
|
|
1922
|
-
|
|
2016
|
+
const srcGas = await this.estimateSendGas(plan, fee, oft);
|
|
2017
|
+
return {
|
|
2018
|
+
...fee,
|
|
2019
|
+
oft,
|
|
2020
|
+
// What the recipient is actually credited: input minus any OFT fee and
|
|
2021
|
+
// minus dust. Falls back to the input when quoteOFT could not be read.
|
|
2022
|
+
toAmount: _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _42 => _42.amountReceived]), () => ( params.amount)),
|
|
2023
|
+
srcGas,
|
|
2024
|
+
totalCostWei: srcGas ? srcGas.costWei + fee.nativeFee : void 0,
|
|
2025
|
+
estimate
|
|
2026
|
+
};
|
|
1923
2027
|
}
|
|
1924
2028
|
/**
|
|
1925
|
-
* LayerZero messaging fee for a send,
|
|
1926
|
-
*
|
|
2029
|
+
* The LayerZero messaging fee for a send, plus the OFT's own accounting.
|
|
2030
|
+
*
|
|
2031
|
+
* 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 us the fee
|
|
2033
|
+
* breakdown and the exact output amount, not the whole quote.
|
|
1927
2034
|
*/
|
|
1928
|
-
async
|
|
1929
|
-
const
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
const amountLD = _viem.parseUnits.call(void 0, String(amount), src.decimals);
|
|
1934
|
-
try {
|
|
1935
|
-
const { nativeFee, lzTokenFee } = await _viem.createPublicClient.call(void 0, {
|
|
1936
|
-
chain: makeChain(src.id, src.rpc),
|
|
1937
|
-
transport: _viem.http.call(void 0, src.rpc)
|
|
1938
|
-
}).readContract({
|
|
1939
|
-
address: oftAdapter,
|
|
2035
|
+
async quotePathway(plan, method) {
|
|
2036
|
+
const sendParam = this.buildSendParams(plan, 0n);
|
|
2037
|
+
const [msgFee, oft] = await Promise.all([
|
|
2038
|
+
plan.pc.readContract({
|
|
2039
|
+
address: plan.oftAdapter,
|
|
1940
2040
|
abi: OFT_ADAPTER_ABI,
|
|
1941
2041
|
functionName: "quoteSend",
|
|
1942
|
-
args: [
|
|
2042
|
+
args: [sendParam, false]
|
|
2043
|
+
}).catch((err) => {
|
|
2044
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableQuoteError)({
|
|
2045
|
+
provider: "layerzero",
|
|
2046
|
+
shortMessage: plan.nativeDrop > 0n ? `${method}: quoteSend call failed \u2014 a dstNativeDrop over the pathway's executor nativeCap is the usual cause` : `${method}: quoteSend call failed`,
|
|
2047
|
+
cause: err
|
|
2048
|
+
});
|
|
2049
|
+
}),
|
|
2050
|
+
this.readOftQuote(plan, sendParam)
|
|
2051
|
+
]);
|
|
2052
|
+
const { nativeFee, lzTokenFee } = msgFee;
|
|
2053
|
+
return { fee: { nativeFee, lzTokenFee }, oft };
|
|
2054
|
+
}
|
|
2055
|
+
/**
|
|
2056
|
+
* The adapter's own view of a send: accepted range, its fees, and what lands on
|
|
2057
|
+
* the far side. Resolves to `undefined` rather than throwing — see `quoteSend`.
|
|
2058
|
+
*/
|
|
2059
|
+
async readOftQuote(plan, sendParam) {
|
|
2060
|
+
try {
|
|
2061
|
+
const [limit, feeDetails, receipt] = await plan.pc.readContract({
|
|
2062
|
+
address: plan.oftAdapter,
|
|
2063
|
+
abi: OFT_ADAPTER_ABI,
|
|
2064
|
+
functionName: "quoteOFT",
|
|
2065
|
+
args: [sendParam]
|
|
2066
|
+
});
|
|
2067
|
+
const decimals = plan.srcToken.decimals;
|
|
2068
|
+
return {
|
|
2069
|
+
amountSentLD: receipt.amountSentLD,
|
|
2070
|
+
amountReceivedLD: receipt.amountReceivedLD,
|
|
2071
|
+
amountReceived: Number(_viem.formatUnits.call(void 0, receipt.amountReceivedLD, decimals)),
|
|
2072
|
+
fees: feeDetails.map((detail) => ({
|
|
2073
|
+
amountLD: detail.feeAmountLD,
|
|
2074
|
+
amount: Number(_viem.formatUnits.call(void 0, detail.feeAmountLD, decimals)),
|
|
2075
|
+
description: detail.description
|
|
2076
|
+
})),
|
|
2077
|
+
minAmountLD: limit.minAmountLD,
|
|
2078
|
+
maxAmountLD: limit.maxAmountLD
|
|
2079
|
+
};
|
|
2080
|
+
} catch (e5) {
|
|
2081
|
+
return void 0;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
/**
|
|
2085
|
+
* Source-chain cost of the `send` transaction.
|
|
2086
|
+
*
|
|
2087
|
+
* Simulating the real call is the only honest answer, and it needs a sender with
|
|
2088
|
+
* the allowance and the native balance already in place — which a quote taken
|
|
2089
|
+
* before approving does not have. When the simulation reverts, fall back to a
|
|
2090
|
+
* measured constant so the caller still has a cost to show, flagged as such.
|
|
2091
|
+
*/
|
|
2092
|
+
async estimateSendGas(plan, fee, oft) {
|
|
2093
|
+
const gasPriceWei = await this.gasPrice(plan);
|
|
2094
|
+
if (gasPriceWei === void 0) return void 0;
|
|
2095
|
+
let gas = FALLBACK_SEND_GAS;
|
|
2096
|
+
let source = "fallback";
|
|
2097
|
+
const account = this.signerAddress();
|
|
2098
|
+
if (account) {
|
|
2099
|
+
try {
|
|
2100
|
+
gas = await plan.pc.estimateContractGas({
|
|
2101
|
+
address: plan.oftAdapter,
|
|
2102
|
+
abi: OFT_ADAPTER_ABI,
|
|
2103
|
+
functionName: "send",
|
|
2104
|
+
args: [
|
|
2105
|
+
this.buildSendParams(plan, _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _43 => _43.amountReceivedLD]), () => ( plan.amountLD))),
|
|
2106
|
+
fee,
|
|
2107
|
+
account
|
|
2108
|
+
],
|
|
2109
|
+
account,
|
|
2110
|
+
value: fee.nativeFee
|
|
2111
|
+
});
|
|
2112
|
+
source = "simulated";
|
|
2113
|
+
} catch (e6) {
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return { gas, gasPriceWei, costWei: gas * gasPriceWei, source };
|
|
2117
|
+
}
|
|
2118
|
+
/** Price per gas unit on the source chain, or undefined if the RPC won't say. */
|
|
2119
|
+
async gasPrice(plan) {
|
|
2120
|
+
try {
|
|
2121
|
+
const fees = await plan.pc.estimateFeesPerGas();
|
|
2122
|
+
const price = _nullishCoalesce(fees.maxFeePerGas, () => ( fees.gasPrice));
|
|
2123
|
+
if (price !== void 0) return price;
|
|
2124
|
+
} catch (e7) {
|
|
2125
|
+
}
|
|
2126
|
+
try {
|
|
2127
|
+
return await plan.pc.getGasPrice();
|
|
2128
|
+
} catch (e8) {
|
|
2129
|
+
return void 0;
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
/**
|
|
2133
|
+
* Top the adapter's allowance up to `amountLD` when it is short. Only the
|
|
2134
|
+
* lockbox chain reaches here — remote deployments burn from the caller.
|
|
2135
|
+
*/
|
|
2136
|
+
async ensureAllowance(plan, wc, owner, amountLD) {
|
|
2137
|
+
const { src, asset, srcToken, oftAdapter, pc, chain: srcChain } = plan;
|
|
2138
|
+
const allowance = await pc.readContract({
|
|
2139
|
+
address: srcToken.address,
|
|
2140
|
+
abi: _viem.erc20Abi,
|
|
2141
|
+
functionName: "allowance",
|
|
2142
|
+
args: [owner, oftAdapter]
|
|
2143
|
+
});
|
|
2144
|
+
if (allowance >= amountLD) return;
|
|
2145
|
+
let approveHash;
|
|
2146
|
+
try {
|
|
2147
|
+
approveHash = await wc.writeContract({
|
|
2148
|
+
address: srcToken.address,
|
|
2149
|
+
abi: _viem.erc20Abi,
|
|
2150
|
+
functionName: "approve",
|
|
2151
|
+
args: [oftAdapter, amountLD],
|
|
2152
|
+
account: wc.account,
|
|
2153
|
+
chain: srcChain
|
|
1943
2154
|
});
|
|
1944
|
-
return { nativeFee, lzTokenFee };
|
|
1945
2155
|
} catch (err) {
|
|
1946
|
-
throw new (0, _chunkQQ26UI3Fcjs.
|
|
1947
|
-
|
|
1948
|
-
shortMessage:
|
|
2156
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableTransactionError)({
|
|
2157
|
+
phase: "approve",
|
|
2158
|
+
shortMessage: `bridge: ${asset} approve failed`,
|
|
2159
|
+
chainId: src.id,
|
|
1949
2160
|
cause: err
|
|
1950
2161
|
});
|
|
1951
2162
|
}
|
|
2163
|
+
const approveReceipt = await pc.waitForTransactionReceipt({ hash: approveHash });
|
|
2164
|
+
if (approveReceipt.status === "reverted") {
|
|
2165
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableTransactionError)({
|
|
2166
|
+
phase: "approve",
|
|
2167
|
+
shortMessage: `bridge: ${asset} approve reverted on-chain`,
|
|
2168
|
+
txHash: approveReceipt.transactionHash,
|
|
2169
|
+
chainId: src.id
|
|
2170
|
+
});
|
|
2171
|
+
}
|
|
1952
2172
|
}
|
|
1953
|
-
async bridge(
|
|
1954
|
-
const from =
|
|
2173
|
+
async bridge(params) {
|
|
2174
|
+
const from = this.signerAddress();
|
|
1955
2175
|
if (!from) {
|
|
1956
2176
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
1957
2177
|
"signer",
|
|
@@ -1959,17 +2179,13 @@ var LayerZeroService = class {
|
|
|
1959
2179
|
"bridge: requires a signer \u2014 set walletClient or account in StableConfig"
|
|
1960
2180
|
);
|
|
1961
2181
|
}
|
|
1962
|
-
const
|
|
1963
|
-
|
|
1964
|
-
const { src, dst } = this.resolveChains(fromChain, toChain, fromToken, toToken);
|
|
1965
|
-
const oftAdapter = src.oftAdapter;
|
|
1966
|
-
const srcChain = makeChain(src.id, src.rpc);
|
|
2182
|
+
const plan = this.plan({ ...params, recipient: _nullishCoalesce(params.recipient, () => ( from)) }, "bridge");
|
|
2183
|
+
const { src, srcToken, oftAdapter, amountLD, chain: srcChain } = plan;
|
|
1967
2184
|
const wc = _nullishCoalesce(this.config.walletClient, () => ( _viem.createWalletClient.call(void 0, {
|
|
1968
2185
|
account: this.config.account,
|
|
1969
2186
|
chain: srcChain,
|
|
1970
2187
|
transport: _nullishCoalesce(this.config.transport, () => ( _viem.http.call(void 0, src.rpc)))
|
|
1971
2188
|
})));
|
|
1972
|
-
const pc = _viem.createPublicClient.call(void 0, { chain: srcChain, transport: _viem.http.call(void 0, src.rpc) });
|
|
1973
2189
|
try {
|
|
1974
2190
|
await wc.switchChain({ id: src.id });
|
|
1975
2191
|
} catch (err) {
|
|
@@ -1980,43 +2196,11 @@ var LayerZeroService = class {
|
|
|
1980
2196
|
cause: err
|
|
1981
2197
|
});
|
|
1982
2198
|
}
|
|
1983
|
-
const
|
|
1984
|
-
const
|
|
1985
|
-
const
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
abi: _viem.erc20Abi,
|
|
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: _viem.erc20Abi,
|
|
1998
|
-
functionName: "approve",
|
|
1999
|
-
args: [oftAdapter, amountLD],
|
|
2000
|
-
account: wc.account,
|
|
2001
|
-
chain: srcChain
|
|
2002
|
-
});
|
|
2003
|
-
} catch (err) {
|
|
2004
|
-
throw new (0, _chunkQQ26UI3Fcjs.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 (0, _chunkQQ26UI3Fcjs.StableTransactionError)({
|
|
2014
|
-
phase: "approve",
|
|
2015
|
-
shortMessage: "bridge: USDT0 approve reverted on-chain",
|
|
2016
|
-
txHash: approveReceipt.transactionHash,
|
|
2017
|
-
chainId: src.id
|
|
2018
|
-
});
|
|
2019
|
-
}
|
|
2199
|
+
const quote = usableQuote(params.quote, amountLD);
|
|
2200
|
+
const { nativeFee, lzTokenFee, oft } = _optionalChain([quote, 'optionalAccess', _44 => _44.nativeFee]) !== void 0 && _optionalChain([quote, 'optionalAccess', _45 => _45.lzTokenFee]) !== void 0 ? { nativeFee: quote.nativeFee, lzTokenFee: quote.lzTokenFee, oft: quote.oft } : await this.quotePathway(plan, "bridge").then((r) => ({ ...r.fee, oft: r.oft }));
|
|
2201
|
+
const sendParams = this.buildSendParams(plan, _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _46 => _46.amountReceivedLD]), () => ( amountLD)));
|
|
2202
|
+
if (srcToken.approvalRequired !== false) {
|
|
2203
|
+
await this.ensureAllowance(plan, wc, from, amountLD);
|
|
2020
2204
|
}
|
|
2021
2205
|
try {
|
|
2022
2206
|
const hash = await wc.writeContract({
|
|
@@ -2028,7 +2212,7 @@ var LayerZeroService = class {
|
|
|
2028
2212
|
account: wc.account,
|
|
2029
2213
|
chain: srcChain
|
|
2030
2214
|
});
|
|
2031
|
-
return { txHash: hash, toAmount: amount };
|
|
2215
|
+
return { txHash: hash, toAmount: _nullishCoalesce(_optionalChain([oft, 'optionalAccess', _47 => _47.amountReceived]), () => ( params.amount)) };
|
|
2032
2216
|
} catch (err) {
|
|
2033
2217
|
throw new (0, _chunkQQ26UI3Fcjs.StableTransactionError)({
|
|
2034
2218
|
phase: "send",
|
|
@@ -2052,18 +2236,26 @@ var LayerZeroService = class {
|
|
|
2052
2236
|
* computes to ~15s (60 blocks × 0.25s) while real deliveries take ~18min, because
|
|
2053
2237
|
* the DVNs wait for the L2 batch to finalize on L1.
|
|
2054
2238
|
*/
|
|
2055
|
-
async estimateBridgeTime({
|
|
2239
|
+
async estimateBridgeTime({
|
|
2240
|
+
fromChain,
|
|
2241
|
+
toChain,
|
|
2242
|
+
fromToken,
|
|
2243
|
+
toToken
|
|
2244
|
+
}) {
|
|
2056
2245
|
const src = BRIDGE_CHAIN_CONFIGS[fromChain];
|
|
2057
2246
|
const dst = BRIDGE_CHAIN_CONFIGS[toChain];
|
|
2058
|
-
|
|
2247
|
+
const from = _nullishCoalesce(fromToken, () => ( _optionalChain([src, 'optionalAccess', _48 => _48.tokens, 'access', _49 => _49.usdt0, 'optionalAccess', _50 => _50.address])));
|
|
2248
|
+
const to = _nullishCoalesce(toToken, () => ( _optionalChain([dst, 'optionalAccess', _51 => _51.tokens, 'access', _52 => _52.usdt0, 'optionalAccess', _53 => _53.address])));
|
|
2249
|
+
if (!(src && from)) {
|
|
2059
2250
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)("fromChain", fromChain, `estimateBridgeTime: no OFT adapter for "${fromChain}"`);
|
|
2060
2251
|
}
|
|
2061
|
-
if (!
|
|
2252
|
+
if (!(dst && to)) {
|
|
2062
2253
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)("toChain", toChain, `estimateBridgeTime: no OFT adapter for "${toChain}"`);
|
|
2063
2254
|
}
|
|
2255
|
+
const { srcToken, dstToken } = this.resolveRoute(fromChain, toChain, from, to);
|
|
2064
2256
|
const [uln, observedSeconds] = await Promise.all([
|
|
2065
|
-
this.getUlnConfig(src, dst).catch(() => void 0),
|
|
2066
|
-
this.observedBridgeSeconds(src, dst).catch(() => void 0)
|
|
2257
|
+
this.getUlnConfig(src, dst, srcToken.oftAdapter).catch(() => void 0),
|
|
2258
|
+
this.observedBridgeSeconds(src, dst, srcToken.oftAdapter, dstToken.oftAdapter).catch(() => void 0)
|
|
2067
2259
|
]);
|
|
2068
2260
|
const dvnCount = uln ? uln.requiredDVNCount + uln.optionalDVNCount : void 0;
|
|
2069
2261
|
let formulaSeconds;
|
|
@@ -2085,7 +2277,7 @@ var LayerZeroService = class {
|
|
|
2085
2277
|
source: observedSeconds !== void 0 ? "observed" : "formula",
|
|
2086
2278
|
observedSeconds,
|
|
2087
2279
|
formulaSeconds,
|
|
2088
|
-
confirmations: Number.isFinite(_optionalChain([uln, 'optionalAccess',
|
|
2280
|
+
confirmations: Number.isFinite(_optionalChain([uln, 'optionalAccess', _54 => _54.confirmations])) ? _optionalChain([uln, 'optionalAccess', _55 => _55.confirmations]) : void 0,
|
|
2089
2281
|
dvnCount: Number.isFinite(dvnCount) ? dvnCount : void 0
|
|
2090
2282
|
};
|
|
2091
2283
|
}
|
|
@@ -2098,7 +2290,7 @@ var LayerZeroService = class {
|
|
|
2098
2290
|
const scanUrl = `${LZ_SCAN_UI}/tx/${srcTxHash}`;
|
|
2099
2291
|
let message;
|
|
2100
2292
|
try {
|
|
2101
|
-
message = await _asyncOptionalChain([(await scanFetch(`/messages/tx/${srcTxHash}`)), 'optionalAccess', async
|
|
2293
|
+
message = await _asyncOptionalChain([(await scanFetch(`/messages/tx/${srcTxHash}`)), 'optionalAccess', async _56 => _56.data, 'optionalAccess', async _57 => _57[0]]);
|
|
2102
2294
|
} catch (err) {
|
|
2103
2295
|
if (err instanceof ScanHttpError && err.status === 404) {
|
|
2104
2296
|
return { state: "pending", srcTxHash, scanUrl };
|
|
@@ -2110,24 +2302,23 @@ var LayerZeroService = class {
|
|
|
2110
2302
|
});
|
|
2111
2303
|
}
|
|
2112
2304
|
if (!message) return { state: "pending", srcTxHash, scanUrl };
|
|
2113
|
-
const raw = _nullishCoalesce(_optionalChain([message, 'access',
|
|
2114
|
-
const sentAt = _optionalChain([message, 'access',
|
|
2305
|
+
const raw = _nullishCoalesce(_optionalChain([message, 'access', _58 => _58.status, 'optionalAccess', _59 => _59.name]), () => ( ""));
|
|
2306
|
+
const sentAt = _optionalChain([message, 'access', _60 => _60.source, 'optionalAccess', _61 => _61.tx, 'optionalAccess', _62 => _62.blockTimestamp]);
|
|
2115
2307
|
return {
|
|
2116
2308
|
// Everything terminal that is not DELIVERED means the tokens will not land
|
|
2117
2309
|
// on their own; `raw` carries which of those it was.
|
|
2118
2310
|
state: raw === "DELIVERED" ? "delivered" : TERMINAL_FAILURE_STATUSES.has(raw) ? "failed" : "inflight",
|
|
2119
2311
|
raw,
|
|
2120
2312
|
srcTxHash,
|
|
2121
|
-
dstTxHash: _optionalChain([message, 'access',
|
|
2313
|
+
dstTxHash: _optionalChain([message, 'access', _63 => _63.destination, 'optionalAccess', _64 => _64.tx, 'optionalAccess', _65 => _65.txHash]),
|
|
2122
2314
|
elapsedSeconds: sentAt ? Math.max(0, Math.floor(Date.now() / 1e3) - sentAt) : void 0,
|
|
2123
2315
|
scanUrl
|
|
2124
2316
|
};
|
|
2125
2317
|
}
|
|
2126
2318
|
/** 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 () => {
|
|
2319
|
+
async getUlnConfig(src, dst, oapp) {
|
|
2320
|
+
return cached(`uln:${src.lzEid}-${dst.lzEid}-${oapp.toLowerCase()}`, CACHE_TTL_MS, async () => {
|
|
2129
2321
|
const pc = _viem.createPublicClient.call(void 0, { chain: makeChain(src.id, src.rpc), transport: _viem.http.call(void 0, src.rpc) });
|
|
2130
|
-
const oapp = src.oftAdapter;
|
|
2131
2322
|
const endpoint = await pc.readContract({ address: oapp, abi: OAPP_ABI, functionName: "endpoint" });
|
|
2132
2323
|
const sendLib = await pc.readContract({
|
|
2133
2324
|
address: endpoint,
|
|
@@ -2149,11 +2340,11 @@ var LayerZeroService = class {
|
|
|
2149
2340
|
});
|
|
2150
2341
|
}
|
|
2151
2342
|
/** Median delivery time of recently delivered messages on this pathway, in seconds. */
|
|
2152
|
-
async observedBridgeSeconds(src, dst) {
|
|
2153
|
-
const pathwayId = `${src.lzEid}-${dst.lzEid}-${
|
|
2343
|
+
async observedBridgeSeconds(src, dst, srcOapp, dstOapp) {
|
|
2344
|
+
const pathwayId = `${src.lzEid}-${dst.lzEid}-${srcOapp.toLowerCase()}-${dstOapp.toLowerCase()}`;
|
|
2154
2345
|
return cached(`observed:${pathwayId}`, CACHE_TTL_MS, async () => {
|
|
2155
2346
|
const { data } = await scanFetch(`/messages/pathway/${pathwayId}?limit=50`);
|
|
2156
|
-
const durations = (_nullishCoalesce(data, () => ( []))).filter((m) => _optionalChain([m, 'access',
|
|
2347
|
+
const durations = (_nullishCoalesce(data, () => ( []))).filter((m) => _optionalChain([m, 'access', _66 => _66.status, 'optionalAccess', _67 => _67.name]) === "DELIVERED").map((m) => (_nullishCoalesce(_optionalChain([m, 'access', _68 => _68.destination, 'optionalAccess', _69 => _69.tx, 'optionalAccess', _70 => _70.blockTimestamp]), () => ( 0))) - (_nullishCoalesce(_optionalChain([m, 'access', _71 => _71.source, 'optionalAccess', _72 => _72.tx, 'optionalAccess', _73 => _73.blockTimestamp]), () => ( 0)))).filter((d) => d > 0);
|
|
2157
2348
|
return durations.length >= 3 ? Math.round(median(durations)) : void 0;
|
|
2158
2349
|
});
|
|
2159
2350
|
}
|
|
@@ -2180,37 +2371,95 @@ var LayerZeroService = class {
|
|
|
2180
2371
|
);
|
|
2181
2372
|
}
|
|
2182
2373
|
}
|
|
2183
|
-
|
|
2374
|
+
/**
|
|
2375
|
+
* Resolve a bridge request to one OFT mesh and its two endpoints.
|
|
2376
|
+
*
|
|
2377
|
+
* Both sides must name the same asset. An OFT escrows one specific ERC-20 and
|
|
2378
|
+
* mints its own peer on the far side — it cannot hand back a different token,
|
|
2379
|
+
* so a USDT0→XAUt0 request is a trade, not a bridge, and belongs to LI.FI.
|
|
2380
|
+
*/
|
|
2381
|
+
resolveRoute(fromChain, toChain, fromToken, toToken) {
|
|
2184
2382
|
const src = BRIDGE_CHAIN_CONFIGS[fromChain];
|
|
2185
2383
|
const dst = BRIDGE_CHAIN_CONFIGS[toChain];
|
|
2186
2384
|
if (!src) throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)("fromChain", fromChain, `Unsupported source chain: "${fromChain}"`);
|
|
2187
2385
|
if (!dst) throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)("toChain", toChain, `Unsupported destination chain: "${toChain}"`);
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
}
|
|
2191
|
-
if (fromToken.toLowerCase() !== src.usdt.toLowerCase()) {
|
|
2386
|
+
const asset = bridgeAssetFor(src, fromToken);
|
|
2387
|
+
if (!asset) {
|
|
2192
2388
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2193
2389
|
"fromToken",
|
|
2194
2390
|
fromToken,
|
|
2195
|
-
`
|
|
2391
|
+
`Native OFT bridge does not recognize "${fromToken}" on "${fromChain}" \u2014 it moves ${describeAssets(src)}. Use route "lifi" to bridge other tokens.`
|
|
2196
2392
|
);
|
|
2197
2393
|
}
|
|
2198
|
-
|
|
2394
|
+
const srcToken = src.tokens[asset];
|
|
2395
|
+
const dstToken = dst.tokens[asset];
|
|
2396
|
+
if (!dstToken) {
|
|
2397
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2398
|
+
"toChain",
|
|
2399
|
+
toChain,
|
|
2400
|
+
`Native OFT bridge cannot deliver ${asset} to "${toChain}" \u2014 no ${asset} deployment there. Use route "lifi" instead.`
|
|
2401
|
+
);
|
|
2402
|
+
}
|
|
2403
|
+
if (dstToken.address.toLowerCase() !== toToken.toLowerCase()) {
|
|
2199
2404
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2200
2405
|
"toToken",
|
|
2201
2406
|
toToken,
|
|
2202
|
-
`
|
|
2407
|
+
`Native OFT bridge moves ${asset} to itself \u2014 toToken must be ${dstToken.address} on "${toChain}", got "${toToken}". Use route "lifi" to bridge between different tokens.`
|
|
2203
2408
|
);
|
|
2204
2409
|
}
|
|
2205
|
-
return { src, dst };
|
|
2410
|
+
return { src, dst, asset, srcToken, dstToken };
|
|
2206
2411
|
}
|
|
2207
|
-
|
|
2412
|
+
/**
|
|
2413
|
+
* Validate a request and resolve it to a single OFT pathway. No network calls —
|
|
2414
|
+
* everything here is config, arithmetic and encoding.
|
|
2415
|
+
*/
|
|
2416
|
+
plan(params, method) {
|
|
2417
|
+
const { fromChain, toChain, fromToken, toToken, amount, recipient, dstNativeDrop } = params;
|
|
2418
|
+
const recipientAddr = _nullishCoalesce(recipient, () => ( ZERO_ADDRESS));
|
|
2419
|
+
this.validateBridgeParams({ fromChain, toChain, amount, recipient: recipientAddr }, method);
|
|
2420
|
+
if (dstNativeDrop !== void 0 && dstNativeDrop < 0n) {
|
|
2421
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2422
|
+
"dstNativeDrop",
|
|
2423
|
+
dstNativeDrop,
|
|
2424
|
+
`${method}: dstNativeDrop must not be negative`
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
const { src, dst, asset, srcToken, dstToken } = this.resolveRoute(
|
|
2428
|
+
fromChain,
|
|
2429
|
+
toChain,
|
|
2430
|
+
fromToken,
|
|
2431
|
+
toToken
|
|
2432
|
+
);
|
|
2433
|
+
const chain = makeChain(src.id, src.rpc);
|
|
2434
|
+
return {
|
|
2435
|
+
src,
|
|
2436
|
+
dst,
|
|
2437
|
+
asset,
|
|
2438
|
+
srcToken,
|
|
2439
|
+
dstToken,
|
|
2440
|
+
oftAdapter: srcToken.oftAdapter,
|
|
2441
|
+
amountLD: _viem.parseUnits.call(void 0, String(amount), srcToken.decimals),
|
|
2442
|
+
recipient: recipientAddr,
|
|
2443
|
+
nativeDrop: _nullishCoalesce(dstNativeDrop, () => ( 0n)),
|
|
2444
|
+
chain,
|
|
2445
|
+
pc: _viem.createPublicClient.call(void 0, { chain, transport: _viem.http.call(void 0, src.rpc) })
|
|
2446
|
+
};
|
|
2447
|
+
}
|
|
2448
|
+
/** The address that will sign, or undefined when this service has no signer. */
|
|
2449
|
+
signerAddress() {
|
|
2450
|
+
return _nullishCoalesce(_optionalChain([this, 'access', _74 => _74.config, 'access', _75 => _75.walletClient, 'optionalAccess', _76 => _76.account, 'optionalAccess', _77 => _77.address]), () => ( _optionalChain([this, 'access', _78 => _78.config, 'access', _79 => _79.account, 'optionalAccess', _80 => _80.address])));
|
|
2451
|
+
}
|
|
2452
|
+
/**
|
|
2453
|
+
* `SendParam` for one call. `minAmountLD` is the caller's slippage floor: 0 when
|
|
2454
|
+
* asking what a send would yield, and the quoted output when actually sending.
|
|
2455
|
+
*/
|
|
2456
|
+
buildSendParams(plan, minAmountLD) {
|
|
2208
2457
|
return {
|
|
2209
|
-
dstEid: dst.lzEid,
|
|
2210
|
-
to: _viem.padHex.call(void 0, recipient, { dir: "left", size: 32 }),
|
|
2211
|
-
amountLD,
|
|
2212
|
-
minAmountLD
|
|
2213
|
-
extraOptions: buildLzOptions(),
|
|
2458
|
+
dstEid: plan.dst.lzEid,
|
|
2459
|
+
to: _viem.padHex.call(void 0, plan.recipient, { dir: "left", size: 32 }),
|
|
2460
|
+
amountLD: plan.amountLD,
|
|
2461
|
+
minAmountLD,
|
|
2462
|
+
extraOptions: buildLzOptions(0n, plan.nativeDrop, plan.recipient),
|
|
2214
2463
|
composeMsg: "0x",
|
|
2215
2464
|
oftCmd: "0x"
|
|
2216
2465
|
};
|
|
@@ -2218,21 +2467,37 @@ var LayerZeroService = class {
|
|
|
2218
2467
|
};
|
|
2219
2468
|
|
|
2220
2469
|
// src/stable.ts
|
|
2221
|
-
function
|
|
2470
|
+
function isNativeOftRoute(fromChain, toChain, fromToken, toToken) {
|
|
2222
2471
|
const src = BRIDGE_CHAIN_CONFIGS[fromChain];
|
|
2223
2472
|
const dst = BRIDGE_CHAIN_CONFIGS[toChain];
|
|
2224
|
-
|
|
2473
|
+
if (!(src && dst)) return false;
|
|
2474
|
+
const asset = bridgeAssetFor(src, fromToken);
|
|
2475
|
+
if (!asset) return false;
|
|
2476
|
+
const srcToken = src.tokens[asset];
|
|
2477
|
+
const dstToken = dst.tokens[asset];
|
|
2478
|
+
return src.lzOutbound !== false && !!srcToken && srcToken.lzOutbound !== false && !!dstToken && dstToken.address.toLowerCase() === toToken.toLowerCase();
|
|
2225
2479
|
}
|
|
2226
2480
|
function selectBridge(params) {
|
|
2481
|
+
const selected = resolveBridge(params);
|
|
2482
|
+
if (selected === "lifi" && (_nullishCoalesce(params.dstNativeDrop, () => ( 0n))) > 0n) {
|
|
2483
|
+
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2484
|
+
"dstNativeDrop",
|
|
2485
|
+
params.dstNativeDrop,
|
|
2486
|
+
`bridge: dstNativeDrop is only supported on the native OFT route, and ${params.fromChain}\u2192${params.toChain} resolved to LI.FI`
|
|
2487
|
+
);
|
|
2488
|
+
}
|
|
2489
|
+
return selected;
|
|
2490
|
+
}
|
|
2491
|
+
function resolveBridge(params) {
|
|
2227
2492
|
const route = _nullishCoalesce(params.route, () => ( "auto"));
|
|
2228
|
-
if (route === "usdt0") return "
|
|
2493
|
+
if (route === "oft" || route === "usdt0") return "oft";
|
|
2229
2494
|
if (route === "lifi") return "lifi";
|
|
2230
|
-
return
|
|
2495
|
+
return isNativeOftRoute(
|
|
2231
2496
|
params.fromChain,
|
|
2232
2497
|
params.toChain,
|
|
2233
2498
|
params.fromToken,
|
|
2234
2499
|
params.toToken
|
|
2235
|
-
) ? "
|
|
2500
|
+
) ? "oft" : "lifi";
|
|
2236
2501
|
}
|
|
2237
2502
|
function validateTransferParams({
|
|
2238
2503
|
to,
|
|
@@ -2277,7 +2542,7 @@ async function resolveTokenDecimals(publicClient, token, tokenDecimals) {
|
|
|
2277
2542
|
abi: _viem.erc20Abi,
|
|
2278
2543
|
functionName: "decimals"
|
|
2279
2544
|
});
|
|
2280
|
-
} catch (
|
|
2545
|
+
} catch (e9) {
|
|
2281
2546
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2282
2547
|
"tokenDecimals",
|
|
2283
2548
|
void 0,
|
|
@@ -2349,7 +2614,7 @@ function createStable({
|
|
|
2349
2614
|
return morpho;
|
|
2350
2615
|
}
|
|
2351
2616
|
function requireSignerAddress() {
|
|
2352
|
-
const from = _nullishCoalesce(_optionalChain([walletClient, 'optionalAccess',
|
|
2617
|
+
const from = _nullishCoalesce(_optionalChain([walletClient, 'optionalAccess', _81 => _81.account, 'optionalAccess', _82 => _82.address]), () => ( _optionalChain([account, 'optionalAccess', _83 => _83.address])));
|
|
2353
2618
|
if (!from) {
|
|
2354
2619
|
throw new (0, _chunkQQ26UI3Fcjs.StableValidationError)(
|
|
2355
2620
|
"signer",
|
|
@@ -2362,7 +2627,7 @@ function createStable({
|
|
|
2362
2627
|
async function transfer(params) {
|
|
2363
2628
|
validateTransferParams(params);
|
|
2364
2629
|
const { from, to, amount, token, tokenDecimals } = params;
|
|
2365
|
-
const acc = _nullishCoalesce(_nullishCoalesce(_optionalChain([walletClient, 'optionalAccess',
|
|
2630
|
+
const acc = _nullishCoalesce(_nullishCoalesce(_optionalChain([walletClient, 'optionalAccess', _84 => _84.account]), () => ( account)), () => ( from));
|
|
2366
2631
|
const wc = _nullishCoalesce(walletClient, () => ( _viem.createWalletClient.call(void 0, {
|
|
2367
2632
|
account: acc,
|
|
2368
2633
|
chain,
|
|
@@ -2414,8 +2679,10 @@ function createStable({
|
|
|
2414
2679
|
}
|
|
2415
2680
|
return {
|
|
2416
2681
|
transfer,
|
|
2417
|
-
|
|
2418
|
-
|
|
2682
|
+
// `async` so a rejected route (see selectBridge) surfaces as a rejected
|
|
2683
|
+
// promise like every other validation error, not a synchronous throw.
|
|
2684
|
+
quoteBridge: async (params) => selectBridge(params) === "oft" ? lz.quoteBridge(params) : lifi.quoteBridge(params),
|
|
2685
|
+
bridge: async (params) => selectBridge(params) === "oft" ? lz.bridge(params) : lifi.bridge(params),
|
|
2419
2686
|
estimateBridgeTime: (params) => lz.estimateBridgeTime(params),
|
|
2420
2687
|
trackBridge: (srcTxHash) => lz.trackBridge(srcTxHash),
|
|
2421
2688
|
quoteSwap: (params) => lifi.quoteSwap(params),
|
|
@@ -2483,4 +2750,5 @@ function createStableReader(config) {
|
|
|
2483
2750
|
|
|
2484
2751
|
|
|
2485
2752
|
|
|
2486
|
-
|
|
2753
|
+
|
|
2754
|
+
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.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.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;
|