@owney/sdk 0.7.28-beta.4 → 0.7.28-beta.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/dist/index.cjs +204 -19
- package/dist/index.d.cts +80 -1
- package/dist/index.d.ts +80 -1
- package/dist/index.js +204 -19
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -523,23 +523,33 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
|
|
|
523
523
|
function historyCoverage(raw) {
|
|
524
524
|
const chains = /* @__PURE__ */ new Map();
|
|
525
525
|
const assets = /* @__PURE__ */ new Map();
|
|
526
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
526
527
|
for (const date of Object.keys(raw.history ?? {}).sort()) {
|
|
527
528
|
void date;
|
|
528
529
|
const seenChains = /* @__PURE__ */ new Set();
|
|
529
530
|
const seenAssets = /* @__PURE__ */ new Set();
|
|
531
|
+
const seenPairs = /* @__PURE__ */ new Map();
|
|
530
532
|
for (const p of (raw.history ?? {})[date].positions ?? []) {
|
|
531
533
|
const balance = p.balance ?? 0;
|
|
532
534
|
const apy = netApy(p.apy_withFee, p.apy, "apy_withFee");
|
|
533
535
|
if (balance <= 0 || typeof apy !== "number") continue;
|
|
534
536
|
seenChains.add(p.chainId);
|
|
535
|
-
if (p.tokenSymbol)
|
|
537
|
+
if (p.tokenSymbol) {
|
|
538
|
+
const asset = p.tokenSymbol.toUpperCase();
|
|
539
|
+
seenAssets.add(asset);
|
|
540
|
+
seenPairs.set(`${p.chainId}:${asset}`, { chainId: p.chainId, asset });
|
|
541
|
+
}
|
|
536
542
|
}
|
|
537
543
|
for (const c of seenChains) chains.set(c, (chains.get(c) ?? 0) + 1);
|
|
538
544
|
for (const a of seenAssets) assets.set(a, (assets.get(a) ?? 0) + 1);
|
|
545
|
+
for (const [key2, pair] of seenPairs) {
|
|
546
|
+
pairs.set(key2, { ...pair, days: (pairs.get(key2)?.days ?? 0) + 1 });
|
|
547
|
+
}
|
|
539
548
|
}
|
|
540
549
|
return {
|
|
541
550
|
chains: [...chains].map(([chainId, days]) => ({ chainId, days })),
|
|
542
|
-
assets: [...assets].map(([asset, days]) => ({ asset, days }))
|
|
551
|
+
assets: [...assets].map(([asset, days]) => ({ asset, days })),
|
|
552
|
+
pairs: [...pairs.values()]
|
|
543
553
|
};
|
|
544
554
|
}
|
|
545
555
|
function mapApyHistory(raw, chainId, tokenSymbol) {
|
|
@@ -584,6 +594,9 @@ function mapEntries(rawEntries, chainId) {
|
|
|
584
594
|
// "Top up wallet" and for slightly less (gas). `Deposit` already exists in
|
|
585
595
|
// the public HistoryAction union, so no consumer type change is needed.
|
|
586
596
|
"Deposit to protocol": "Deposit",
|
|
597
|
+
// Withdrawing from an async vault (Superform) is logged under its own
|
|
598
|
+
// label and paid out later in a separate batch (ROUT-624).
|
|
599
|
+
"Request async withdrawal": "Withdraw",
|
|
587
600
|
Rebalance: "Rebalance"
|
|
588
601
|
};
|
|
589
602
|
void chainId;
|
|
@@ -626,8 +639,9 @@ function mapEntries(rawEntries, chainId) {
|
|
|
626
639
|
];
|
|
627
640
|
}
|
|
628
641
|
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
642
|
+
const asyncRequest = entry.action === "Request async withdrawal";
|
|
629
643
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
630
|
-
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
644
|
+
const hasAmount = (mappedAction !== "Withdraw" || asyncRequest) && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
631
645
|
const mappedPositions = positions.filter((p) => p.protocol_name).map((p) => ({
|
|
632
646
|
protocol: p.protocol_name,
|
|
633
647
|
pool: p.pool ?? void 0,
|
|
@@ -641,6 +655,7 @@ function mapEntries(rawEntries, chainId) {
|
|
|
641
655
|
newApy: newApy === null ? null : String(newApy),
|
|
642
656
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
643
657
|
...mappedPositions.length ? { positions: mappedPositions } : {},
|
|
658
|
+
...asyncRequest ? { asyncRequest: true } : {},
|
|
644
659
|
transactions: [
|
|
645
660
|
{
|
|
646
661
|
txHashes: entry.transactionHash ? [entry.transactionHash] : [],
|
|
@@ -1281,7 +1296,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1281
1296
|
*/
|
|
1282
1297
|
async resolveWithdrawnAmounts(entries, chainId, recipient) {
|
|
1283
1298
|
const withdrawals = entries.filter(
|
|
1284
|
-
(e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
|
|
1299
|
+
(e) => e.action === "Withdraw" && !e.asyncRequest && e.transactions[0]?.txHashes[0]
|
|
1285
1300
|
);
|
|
1286
1301
|
if (withdrawals.length === 0) return;
|
|
1287
1302
|
const client = this.getPublicClient(chainId);
|
|
@@ -1787,6 +1802,44 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1787
1802
|
);
|
|
1788
1803
|
}
|
|
1789
1804
|
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Read back what `setPoolSelection` wrote (ROUT-650). Zyfai keeps the saved
|
|
1807
|
+
* pools per protocol/chain and the strategy per asset; both are read for the
|
|
1808
|
+
* pairs and assets asked about. A pair still on autoselect, or one whose
|
|
1809
|
+
* lookup fails, is left out so the caller falls back to its default for it.
|
|
1810
|
+
*/
|
|
1811
|
+
async getPoolSelection(params) {
|
|
1812
|
+
const [pairs, strategies] = await Promise.all([
|
|
1813
|
+
Promise.all(
|
|
1814
|
+
params.pairs.map(async ({ protocolId, chainId }) => {
|
|
1815
|
+
try {
|
|
1816
|
+
const current = await this.sdk.getSelectedPools(
|
|
1817
|
+
protocolId,
|
|
1818
|
+
chainId
|
|
1819
|
+
);
|
|
1820
|
+
if (current.autoselect) return null;
|
|
1821
|
+
return { protocolId, chainId, pools: current.pools ?? [] };
|
|
1822
|
+
} catch {
|
|
1823
|
+
return null;
|
|
1824
|
+
}
|
|
1825
|
+
})
|
|
1826
|
+
),
|
|
1827
|
+
Promise.all(
|
|
1828
|
+
params.assets.map(async (asset) => {
|
|
1829
|
+
try {
|
|
1830
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1831
|
+
return current.strategy ? { asset, strategy: current.strategy } : null;
|
|
1832
|
+
} catch {
|
|
1833
|
+
return null;
|
|
1834
|
+
}
|
|
1835
|
+
})
|
|
1836
|
+
)
|
|
1837
|
+
]);
|
|
1838
|
+
return {
|
|
1839
|
+
pairs: pairs.filter((value) => value !== null),
|
|
1840
|
+
strategies: strategies.filter((value) => value !== null)
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1790
1843
|
/**
|
|
1791
1844
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1792
1845
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -2884,6 +2937,33 @@ function swapChain(chainId) {
|
|
|
2884
2937
|
return CHAINS[chainId];
|
|
2885
2938
|
}
|
|
2886
2939
|
|
|
2940
|
+
// src/lib/swap/swap.gas-check.ts
|
|
2941
|
+
var CLASSIC_SWAP_GAS = 300000n;
|
|
2942
|
+
var APPROVE_GAS2 = 60000n;
|
|
2943
|
+
var isNative = (address) => address.toLowerCase().startsWith("0xeeee");
|
|
2944
|
+
async function swapGasShortfall(deps, quote) {
|
|
2945
|
+
if (quote.rail !== "classic" || isNative(quote.src.address)) return null;
|
|
2946
|
+
const gas = CLASSIC_SWAP_GAS + APPROVE_GAS2;
|
|
2947
|
+
const [balance, gasPrice] = await Promise.all([
|
|
2948
|
+
deps.readNativeBalance(),
|
|
2949
|
+
deps.getMaxFeePerGas()
|
|
2950
|
+
]);
|
|
2951
|
+
const required = gas * gasPrice;
|
|
2952
|
+
return balance < required ? { chainId: quote.src.chainId, balance, required } : null;
|
|
2953
|
+
}
|
|
2954
|
+
function swapGasError(shortfall, nativeSymbol) {
|
|
2955
|
+
return new OwneyError(
|
|
2956
|
+
"SWAP_INSUFFICIENT_GAS",
|
|
2957
|
+
`This swap needs a little ${nativeSymbol} for network fees, and your wallet has too little. Add some ${nativeSymbol}, or choose a different asset to receive.`,
|
|
2958
|
+
{
|
|
2959
|
+
chainId: shortfall.chainId,
|
|
2960
|
+
symbol: nativeSymbol,
|
|
2961
|
+
balance: shortfall.balance.toString(),
|
|
2962
|
+
required: shortfall.required.toString()
|
|
2963
|
+
}
|
|
2964
|
+
);
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2887
2967
|
// src/lib/swap/swap.arrival.ts
|
|
2888
2968
|
var DEFAULT_TIMEOUT_MS = 18e4;
|
|
2889
2969
|
var DEFAULT_POLL_MS = 4e3;
|
|
@@ -3400,8 +3480,8 @@ async function runClassic(deps, options) {
|
|
|
3400
3480
|
onStage?.("quoting");
|
|
3401
3481
|
debugLog("owney-sdk", "swap: fetching classic calldata");
|
|
3402
3482
|
let { tx } = await deps.api.swapTx(swapTxRequest);
|
|
3403
|
-
const
|
|
3404
|
-
if (!
|
|
3483
|
+
const isNative2 = BigInt(tx.value ?? "0") > 0n;
|
|
3484
|
+
if (!isNative2) {
|
|
3405
3485
|
const needed = amount;
|
|
3406
3486
|
const current = await deps.readAllowance(tx.to);
|
|
3407
3487
|
debugLog("owney-sdk", "swap: allowance", {
|
|
@@ -4467,6 +4547,15 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4467
4547
|
|
|
4468
4548
|
// src/client.ts
|
|
4469
4549
|
var WALLET_CATCHUP_TIMEOUT_MS = 3e4;
|
|
4550
|
+
function shortfallBalance(error, asked) {
|
|
4551
|
+
if (!(error instanceof OwneyError)) return void 0;
|
|
4552
|
+
if (error.code !== "DEPOSIT_INSUFFICIENT_BALANCE") return void 0;
|
|
4553
|
+
const seen = error.details?.balance;
|
|
4554
|
+
if (typeof seen !== "string") return void 0;
|
|
4555
|
+
const balance = BigInt(seen);
|
|
4556
|
+
if (balance <= 0n || balance >= asked) return void 0;
|
|
4557
|
+
return (asked - balance) * 100n <= asked ? balance : void 0;
|
|
4558
|
+
}
|
|
4470
4559
|
function encodeMultiAgentCursor(map) {
|
|
4471
4560
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
4472
4561
|
}
|
|
@@ -5476,6 +5565,19 @@ var OwneySDK = class {
|
|
|
5476
5565
|
chain: dstChain,
|
|
5477
5566
|
transport: swapReadTransport(quote.dst.chainId, this.zyfaiRpcUrls)
|
|
5478
5567
|
});
|
|
5568
|
+
const walletPublic = (0, import_viem9.createPublicClient)({
|
|
5569
|
+
chain: srcChain,
|
|
5570
|
+
transport: (0, import_viem9.custom)(provider)
|
|
5571
|
+
});
|
|
5572
|
+
const signOnSource = (payload) => signWithChainRetry(
|
|
5573
|
+
walletPublic,
|
|
5574
|
+
wallet,
|
|
5575
|
+
quote.src.chainId,
|
|
5576
|
+
() => wallet.signTypedData({
|
|
5577
|
+
account: state.walletAddress,
|
|
5578
|
+
...payload
|
|
5579
|
+
})
|
|
5580
|
+
);
|
|
5479
5581
|
return {
|
|
5480
5582
|
api: this.swapApi(),
|
|
5481
5583
|
// Native-aware, like readSourceBalance below. Native ETH is never a
|
|
@@ -5516,10 +5618,7 @@ var OwneySDK = class {
|
|
|
5516
5618
|
}
|
|
5517
5619
|
return hash;
|
|
5518
5620
|
},
|
|
5519
|
-
signTypedData:
|
|
5520
|
-
account: state.walletAddress,
|
|
5521
|
-
...typedData
|
|
5522
|
-
}),
|
|
5621
|
+
signTypedData: signOnSource,
|
|
5523
5622
|
// Chain-bound like every other read here: the wallet provider's chain is
|
|
5524
5623
|
// not ours to rely on mid-swap.
|
|
5525
5624
|
readSourceBalance: async () => {
|
|
@@ -5576,10 +5675,7 @@ var OwneySDK = class {
|
|
|
5576
5675
|
spender,
|
|
5577
5676
|
value: amount,
|
|
5578
5677
|
chainId: quote.src.chainId,
|
|
5579
|
-
signTypedData:
|
|
5580
|
-
account: state.walletAddress,
|
|
5581
|
-
...payload
|
|
5582
|
-
})
|
|
5678
|
+
signTypedData: signOnSource
|
|
5583
5679
|
}
|
|
5584
5680
|
),
|
|
5585
5681
|
/**
|
|
@@ -5673,6 +5769,38 @@ var OwneySDK = class {
|
|
|
5673
5769
|
const balance = await this.readTokenBalance(chainId, token);
|
|
5674
5770
|
return (balance < received ? balance : received).toString();
|
|
5675
5771
|
}
|
|
5772
|
+
/**
|
|
5773
|
+
* Deposit a swap's output, retrying once at the balance the deposit saw.
|
|
5774
|
+
*
|
|
5775
|
+
* `settleSwapDepositAmount` approves and THEN reads, but the read and the
|
|
5776
|
+
* deposit's own pre-check can disagree: the approval is confirmed through
|
|
5777
|
+
* the wallet's node, the read goes to a pinned RPC, and gas paid in WETH
|
|
5778
|
+
* (MetaMask offers this to a wallet with no ETH) can land after either.
|
|
5779
|
+
* ROUT-618 failed that way with the settle step in place.
|
|
5780
|
+
*
|
|
5781
|
+
* The pre-check reports the balance it saw, and that is the authority, so
|
|
5782
|
+
* a shortfall is retried once at that figure. Only a small one: a node that
|
|
5783
|
+
* has not caught up can read near zero, and depositing that would leave the
|
|
5784
|
+
* rest of the swap stranded behind a "success".
|
|
5785
|
+
*/
|
|
5786
|
+
async depositSwapOutput(options) {
|
|
5787
|
+
const attempt = (amount) => this.deposit({
|
|
5788
|
+
amount,
|
|
5789
|
+
asset: options.asset,
|
|
5790
|
+
...options.agentId ? { agentId: options.agentId } : {}
|
|
5791
|
+
});
|
|
5792
|
+
try {
|
|
5793
|
+
return {
|
|
5794
|
+
deposit: await attempt(options.amount),
|
|
5795
|
+
deposited: options.amount
|
|
5796
|
+
};
|
|
5797
|
+
} catch (error) {
|
|
5798
|
+
const balance = shortfallBalance(error, BigInt(options.amount));
|
|
5799
|
+
if (balance === void 0) throw error;
|
|
5800
|
+
const deposited = balance.toString();
|
|
5801
|
+
return { deposit: await attempt(deposited), deposited };
|
|
5802
|
+
}
|
|
5803
|
+
}
|
|
5676
5804
|
async walletSeesBalance(chainId, token, amount) {
|
|
5677
5805
|
const provider = this.requireConnectedProvider();
|
|
5678
5806
|
const state = this.requireState();
|
|
@@ -5698,9 +5826,39 @@ var OwneySDK = class {
|
|
|
5698
5826
|
* Runs a quoted swap. A named seam rather than an inline `executeSwap` call
|
|
5699
5827
|
* so the deposit half of `swapAndDeposit` can be exercised on its own.
|
|
5700
5828
|
*/
|
|
5701
|
-
runSwap(quote, options) {
|
|
5829
|
+
async runSwap(quote, options) {
|
|
5830
|
+
await this.checkSwapGas(quote);
|
|
5702
5831
|
return executeSwap(this.buildSwapDeps(quote), { quote, ...options });
|
|
5703
5832
|
}
|
|
5833
|
+
/**
|
|
5834
|
+
* Throws SWAP_INSUFFICIENT_GAS when the wallet cannot pay for this swap.
|
|
5835
|
+
*
|
|
5836
|
+
* Only the classic rail is ever refused: it is the one where the user sends
|
|
5837
|
+
* the transactions. Call it on a preview quote to warn BEFORE a withdrawal
|
|
5838
|
+
* moves anything — `withdrawAndSwap` repeats it on its own quote, but by
|
|
5839
|
+
* then the funds have already left the agent (ROUT-622).
|
|
5840
|
+
*/
|
|
5841
|
+
async checkSwapGas(quote) {
|
|
5842
|
+
const state = this.requireState();
|
|
5843
|
+
const chain = swapChain(quote.src.chainId);
|
|
5844
|
+
if (!chain) return;
|
|
5845
|
+
const pub = (0, import_viem9.createPublicClient)({
|
|
5846
|
+
chain,
|
|
5847
|
+
transport: swapReadTransport(quote.src.chainId, this.zyfaiRpcUrls)
|
|
5848
|
+
});
|
|
5849
|
+
const shortfall = await swapGasShortfall(
|
|
5850
|
+
{
|
|
5851
|
+
readNativeBalance: () => pub.getBalance({ address: state.walletAddress }),
|
|
5852
|
+
// The 1559 ceiling, as the wrap reserve reads it.
|
|
5853
|
+
getMaxFeePerGas: async () => {
|
|
5854
|
+
const fees = await pub.estimateFeesPerGas();
|
|
5855
|
+
return fees.maxFeePerGas ?? pub.getGasPrice();
|
|
5856
|
+
}
|
|
5857
|
+
},
|
|
5858
|
+
quote
|
|
5859
|
+
);
|
|
5860
|
+
if (shortfall) throw swapGasError(shortfall, chain.nativeCurrency.symbol);
|
|
5861
|
+
}
|
|
5704
5862
|
/**
|
|
5705
5863
|
* The half of the swap deps that only ever talks to the routing API.
|
|
5706
5864
|
*
|
|
@@ -5772,8 +5930,15 @@ var OwneySDK = class {
|
|
|
5772
5930
|
);
|
|
5773
5931
|
}
|
|
5774
5932
|
await this.ensureSwapChain(entry.chainId);
|
|
5775
|
-
const
|
|
5776
|
-
|
|
5933
|
+
const token = entry.symbol === "WETH" ? SPONSORED_WETH_BY_CHAIN[entry.chainId] : void 0;
|
|
5934
|
+
const amount = token ? await this.settleSwapDepositAmount(
|
|
5935
|
+
entry.chainId,
|
|
5936
|
+
token,
|
|
5937
|
+
entry.symbol,
|
|
5938
|
+
BigInt(entry.received)
|
|
5939
|
+
) : entry.received;
|
|
5940
|
+
const { deposit } = await this.depositSwapOutput({
|
|
5941
|
+
amount,
|
|
5777
5942
|
asset: entry.symbol,
|
|
5778
5943
|
...entry.agentId ? { agentId: entry.agentId } : {}
|
|
5779
5944
|
});
|
|
@@ -6013,12 +6178,12 @@ var OwneySDK = class {
|
|
|
6013
6178
|
options.to.symbol,
|
|
6014
6179
|
BigInt(swap.received)
|
|
6015
6180
|
);
|
|
6016
|
-
const deposit = await this.
|
|
6181
|
+
const { deposit, deposited } = await this.depositSwapOutput({
|
|
6017
6182
|
amount,
|
|
6018
6183
|
asset: options.to.symbol,
|
|
6019
6184
|
...options.agentId ? { agentId: options.agentId } : {}
|
|
6020
6185
|
});
|
|
6021
|
-
return { swap, deposit, deposited
|
|
6186
|
+
return { swap, deposit, deposited };
|
|
6022
6187
|
} catch (error) {
|
|
6023
6188
|
const pending = {
|
|
6024
6189
|
id: `${quote.dst.chainId}-${options.to.symbol}-${Date.now()}`,
|
|
@@ -6122,6 +6287,7 @@ var OwneySDK = class {
|
|
|
6122
6287
|
walletAddress: state.walletAddress
|
|
6123
6288
|
});
|
|
6124
6289
|
await this.ensureSwapChain(quote.src.chainId);
|
|
6290
|
+
await this.checkSwapGas(quote);
|
|
6125
6291
|
const swap = await executeSwap(this.buildSwapDeps(quote), {
|
|
6126
6292
|
quote,
|
|
6127
6293
|
walletAddress: state.walletAddress,
|
|
@@ -6632,6 +6798,25 @@ var OwneySDK = class {
|
|
|
6632
6798
|
}
|
|
6633
6799
|
await agent.setPoolSelection(params.selection);
|
|
6634
6800
|
}
|
|
6801
|
+
/**
|
|
6802
|
+
* The pool selection saved on the user's account (ROUT-650), so the Pools
|
|
6803
|
+
* step can show what applies now rather than the defaults. `pairs` and
|
|
6804
|
+
* `assets` say which protocol/chain lists and strategies to read.
|
|
6805
|
+
*/
|
|
6806
|
+
async getPoolSelection(params) {
|
|
6807
|
+
await this.ensureAgentsInitialized();
|
|
6808
|
+
const agent = this.getAgent(params.agentId ?? "zyfai");
|
|
6809
|
+
if (!agent.getPoolSelection) {
|
|
6810
|
+
throw new OwneyError(
|
|
6811
|
+
"POOL_SELECTION_UNSUPPORTED",
|
|
6812
|
+
`Agent ${agent.id} does not support pool customization`
|
|
6813
|
+
);
|
|
6814
|
+
}
|
|
6815
|
+
return agent.getPoolSelection({
|
|
6816
|
+
pairs: params.pairs,
|
|
6817
|
+
assets: params.assets
|
|
6818
|
+
});
|
|
6819
|
+
}
|
|
6635
6820
|
async getAccountApy({
|
|
6636
6821
|
agentId,
|
|
6637
6822
|
days,
|
package/dist/index.d.cts
CHANGED
|
@@ -563,6 +563,22 @@ type UserPoolSelectionRequest = {
|
|
|
563
563
|
}>;
|
|
564
564
|
selections: UserPoolSelection[];
|
|
565
565
|
};
|
|
566
|
+
/**
|
|
567
|
+
* What a user's account currently has saved (ROUT-650): each asset's strategy,
|
|
568
|
+
* plus the pool list of every protocol/chain pair frozen by an earlier Save.
|
|
569
|
+
* Pairs Zyfai still autoselects are left out, so "no entry" means "default".
|
|
570
|
+
*/
|
|
571
|
+
type SavedPoolSelection = {
|
|
572
|
+
strategies: Array<{
|
|
573
|
+
asset: "USDC" | "WETH";
|
|
574
|
+
strategy: string;
|
|
575
|
+
}>;
|
|
576
|
+
pairs: Array<{
|
|
577
|
+
protocolId: string;
|
|
578
|
+
chainId: number;
|
|
579
|
+
pools: string[];
|
|
580
|
+
}>;
|
|
581
|
+
};
|
|
566
582
|
/** One protocol with its pools for the deposit asset — what the Pools step
|
|
567
583
|
* renders: a protocol row that opens to a list of selectable pools. */
|
|
568
584
|
type PoolCatalogProtocol = {
|
|
@@ -723,6 +739,14 @@ interface ApyCoverage {
|
|
|
723
739
|
asset: string;
|
|
724
740
|
days: number;
|
|
725
741
|
}[];
|
|
742
|
+
/** Each asset on each chain, for a menu that offers the two together
|
|
743
|
+
* (ROUT-647). The lists above cannot say this: USDC on Base and WETH on
|
|
744
|
+
* Arbitrum put both chains and both assets in them, and no WETH on Base. */
|
|
745
|
+
pairs: {
|
|
746
|
+
chainId: number;
|
|
747
|
+
asset: string;
|
|
748
|
+
days: number;
|
|
749
|
+
}[];
|
|
726
750
|
}
|
|
727
751
|
interface AccountAgentApy {
|
|
728
752
|
walletAddress: string;
|
|
@@ -802,6 +826,13 @@ interface AgentHistoryEntry {
|
|
|
802
826
|
transactions: HistoryTransaction[];
|
|
803
827
|
rebalanceLog: RebalanceLog[];
|
|
804
828
|
positions?: AgentHistoryPosition[];
|
|
829
|
+
/**
|
|
830
|
+
* Set on a `Withdraw` that was only requested from an async vault
|
|
831
|
+
* (ROUT-624). The vault pays out in batches later, so the funds have not
|
|
832
|
+
* reached the wallet yet and `transactions[0].amount` is the amount
|
|
833
|
+
* requested.
|
|
834
|
+
*/
|
|
835
|
+
asyncRequest?: true;
|
|
805
836
|
}
|
|
806
837
|
interface OwneyAgentHistory {
|
|
807
838
|
data: AgentHistoryEntry[];
|
|
@@ -914,6 +945,17 @@ interface IAgent {
|
|
|
914
945
|
* (ROUT-569)
|
|
915
946
|
*/
|
|
916
947
|
setPoolSelection?(selection: UserPoolSelectionRequest): Promise<void>;
|
|
948
|
+
/**
|
|
949
|
+
* Read back what `setPoolSelection` saved, for the pairs and assets given,
|
|
950
|
+
* so the Pools step can open on the user's own choices. Optional. (ROUT-650)
|
|
951
|
+
*/
|
|
952
|
+
getPoolSelection?(params: {
|
|
953
|
+
pairs: Array<{
|
|
954
|
+
protocolId: string;
|
|
955
|
+
chainId: number;
|
|
956
|
+
}>;
|
|
957
|
+
assets: Array<"USDC" | "WETH">;
|
|
958
|
+
}): Promise<SavedPoolSelection>;
|
|
917
959
|
deposit(state: ConnectionState, chainId: number, amount: string, asset: OwneySupportedTokens, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
|
|
918
960
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
919
961
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
@@ -1393,12 +1435,36 @@ declare class OwneySDK {
|
|
|
1393
1435
|
* where the sponsor covers the transfer and Permit2 never applies.
|
|
1394
1436
|
*/
|
|
1395
1437
|
private settleSwapDepositAmount;
|
|
1438
|
+
/**
|
|
1439
|
+
* Deposit a swap's output, retrying once at the balance the deposit saw.
|
|
1440
|
+
*
|
|
1441
|
+
* `settleSwapDepositAmount` approves and THEN reads, but the read and the
|
|
1442
|
+
* deposit's own pre-check can disagree: the approval is confirmed through
|
|
1443
|
+
* the wallet's node, the read goes to a pinned RPC, and gas paid in WETH
|
|
1444
|
+
* (MetaMask offers this to a wallet with no ETH) can land after either.
|
|
1445
|
+
* ROUT-618 failed that way with the settle step in place.
|
|
1446
|
+
*
|
|
1447
|
+
* The pre-check reports the balance it saw, and that is the authority, so
|
|
1448
|
+
* a shortfall is retried once at that figure. Only a small one: a node that
|
|
1449
|
+
* has not caught up can read near zero, and depositing that would leave the
|
|
1450
|
+
* rest of the swap stranded behind a "success".
|
|
1451
|
+
*/
|
|
1452
|
+
private depositSwapOutput;
|
|
1396
1453
|
private walletSeesBalance;
|
|
1397
1454
|
/**
|
|
1398
1455
|
* Runs a quoted swap. A named seam rather than an inline `executeSwap` call
|
|
1399
1456
|
* so the deposit half of `swapAndDeposit` can be exercised on its own.
|
|
1400
1457
|
*/
|
|
1401
1458
|
private runSwap;
|
|
1459
|
+
/**
|
|
1460
|
+
* Throws SWAP_INSUFFICIENT_GAS when the wallet cannot pay for this swap.
|
|
1461
|
+
*
|
|
1462
|
+
* Only the classic rail is ever refused: it is the one where the user sends
|
|
1463
|
+
* the transactions. Call it on a preview quote to warn BEFORE a withdrawal
|
|
1464
|
+
* moves anything — `withdrawAndSwap` repeats it on its own quote, but by
|
|
1465
|
+
* then the funds have already left the agent (ROUT-622).
|
|
1466
|
+
*/
|
|
1467
|
+
checkSwapGas(quote: SwapQuote): Promise<void>;
|
|
1402
1468
|
/**
|
|
1403
1469
|
* The half of the swap deps that only ever talks to the routing API.
|
|
1404
1470
|
*
|
|
@@ -1758,6 +1824,19 @@ declare class OwneySDK {
|
|
|
1758
1824
|
selection: UserPoolSelectionRequest;
|
|
1759
1825
|
agentId?: AgentId;
|
|
1760
1826
|
}): Promise<void>;
|
|
1827
|
+
/**
|
|
1828
|
+
* The pool selection saved on the user's account (ROUT-650), so the Pools
|
|
1829
|
+
* step can show what applies now rather than the defaults. `pairs` and
|
|
1830
|
+
* `assets` say which protocol/chain lists and strategies to read.
|
|
1831
|
+
*/
|
|
1832
|
+
getPoolSelection(params: {
|
|
1833
|
+
pairs: Array<{
|
|
1834
|
+
protocolId: string;
|
|
1835
|
+
chainId: number;
|
|
1836
|
+
}>;
|
|
1837
|
+
assets: Array<"USDC" | "WETH">;
|
|
1838
|
+
agentId?: AgentId;
|
|
1839
|
+
}): Promise<SavedPoolSelection>;
|
|
1761
1840
|
getAccountApy({ agentId, days, tokenSymbol, chainId: scope, }: AccountApyOptions): Promise<OwneyAccountApy | AccountAgentApy>;
|
|
1762
1841
|
/**
|
|
1763
1842
|
* Get transaction history for a specific agent, or all agents.
|
|
@@ -1900,4 +1979,4 @@ type StoredOrder = {
|
|
|
1900
1979
|
*/
|
|
1901
1980
|
declare function listOrders(now?: number): StoredOrder[];
|
|
1902
1981
|
|
|
1903
|
-
export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
|
|
1982
|
+
export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SavedPoolSelection, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
|
package/dist/index.d.ts
CHANGED
|
@@ -563,6 +563,22 @@ type UserPoolSelectionRequest = {
|
|
|
563
563
|
}>;
|
|
564
564
|
selections: UserPoolSelection[];
|
|
565
565
|
};
|
|
566
|
+
/**
|
|
567
|
+
* What a user's account currently has saved (ROUT-650): each asset's strategy,
|
|
568
|
+
* plus the pool list of every protocol/chain pair frozen by an earlier Save.
|
|
569
|
+
* Pairs Zyfai still autoselects are left out, so "no entry" means "default".
|
|
570
|
+
*/
|
|
571
|
+
type SavedPoolSelection = {
|
|
572
|
+
strategies: Array<{
|
|
573
|
+
asset: "USDC" | "WETH";
|
|
574
|
+
strategy: string;
|
|
575
|
+
}>;
|
|
576
|
+
pairs: Array<{
|
|
577
|
+
protocolId: string;
|
|
578
|
+
chainId: number;
|
|
579
|
+
pools: string[];
|
|
580
|
+
}>;
|
|
581
|
+
};
|
|
566
582
|
/** One protocol with its pools for the deposit asset — what the Pools step
|
|
567
583
|
* renders: a protocol row that opens to a list of selectable pools. */
|
|
568
584
|
type PoolCatalogProtocol = {
|
|
@@ -723,6 +739,14 @@ interface ApyCoverage {
|
|
|
723
739
|
asset: string;
|
|
724
740
|
days: number;
|
|
725
741
|
}[];
|
|
742
|
+
/** Each asset on each chain, for a menu that offers the two together
|
|
743
|
+
* (ROUT-647). The lists above cannot say this: USDC on Base and WETH on
|
|
744
|
+
* Arbitrum put both chains and both assets in them, and no WETH on Base. */
|
|
745
|
+
pairs: {
|
|
746
|
+
chainId: number;
|
|
747
|
+
asset: string;
|
|
748
|
+
days: number;
|
|
749
|
+
}[];
|
|
726
750
|
}
|
|
727
751
|
interface AccountAgentApy {
|
|
728
752
|
walletAddress: string;
|
|
@@ -802,6 +826,13 @@ interface AgentHistoryEntry {
|
|
|
802
826
|
transactions: HistoryTransaction[];
|
|
803
827
|
rebalanceLog: RebalanceLog[];
|
|
804
828
|
positions?: AgentHistoryPosition[];
|
|
829
|
+
/**
|
|
830
|
+
* Set on a `Withdraw` that was only requested from an async vault
|
|
831
|
+
* (ROUT-624). The vault pays out in batches later, so the funds have not
|
|
832
|
+
* reached the wallet yet and `transactions[0].amount` is the amount
|
|
833
|
+
* requested.
|
|
834
|
+
*/
|
|
835
|
+
asyncRequest?: true;
|
|
805
836
|
}
|
|
806
837
|
interface OwneyAgentHistory {
|
|
807
838
|
data: AgentHistoryEntry[];
|
|
@@ -914,6 +945,17 @@ interface IAgent {
|
|
|
914
945
|
* (ROUT-569)
|
|
915
946
|
*/
|
|
916
947
|
setPoolSelection?(selection: UserPoolSelectionRequest): Promise<void>;
|
|
948
|
+
/**
|
|
949
|
+
* Read back what `setPoolSelection` saved, for the pairs and assets given,
|
|
950
|
+
* so the Pools step can open on the user's own choices. Optional. (ROUT-650)
|
|
951
|
+
*/
|
|
952
|
+
getPoolSelection?(params: {
|
|
953
|
+
pairs: Array<{
|
|
954
|
+
protocolId: string;
|
|
955
|
+
chainId: number;
|
|
956
|
+
}>;
|
|
957
|
+
assets: Array<"USDC" | "WETH">;
|
|
958
|
+
}): Promise<SavedPoolSelection>;
|
|
917
959
|
deposit(state: ConnectionState, chainId: number, amount: string, asset: OwneySupportedTokens, depositCallback?: DepositCallback): Promise<OwneyDepositResult>;
|
|
918
960
|
withdraw(state: ConnectionState, chainId: number, token: OwneySupportedTokens, amount?: string): Promise<AgentWithdrawResult>;
|
|
919
961
|
getBalances(state: ConnectionState, chainId: number): Promise<AgentBalance>;
|
|
@@ -1393,12 +1435,36 @@ declare class OwneySDK {
|
|
|
1393
1435
|
* where the sponsor covers the transfer and Permit2 never applies.
|
|
1394
1436
|
*/
|
|
1395
1437
|
private settleSwapDepositAmount;
|
|
1438
|
+
/**
|
|
1439
|
+
* Deposit a swap's output, retrying once at the balance the deposit saw.
|
|
1440
|
+
*
|
|
1441
|
+
* `settleSwapDepositAmount` approves and THEN reads, but the read and the
|
|
1442
|
+
* deposit's own pre-check can disagree: the approval is confirmed through
|
|
1443
|
+
* the wallet's node, the read goes to a pinned RPC, and gas paid in WETH
|
|
1444
|
+
* (MetaMask offers this to a wallet with no ETH) can land after either.
|
|
1445
|
+
* ROUT-618 failed that way with the settle step in place.
|
|
1446
|
+
*
|
|
1447
|
+
* The pre-check reports the balance it saw, and that is the authority, so
|
|
1448
|
+
* a shortfall is retried once at that figure. Only a small one: a node that
|
|
1449
|
+
* has not caught up can read near zero, and depositing that would leave the
|
|
1450
|
+
* rest of the swap stranded behind a "success".
|
|
1451
|
+
*/
|
|
1452
|
+
private depositSwapOutput;
|
|
1396
1453
|
private walletSeesBalance;
|
|
1397
1454
|
/**
|
|
1398
1455
|
* Runs a quoted swap. A named seam rather than an inline `executeSwap` call
|
|
1399
1456
|
* so the deposit half of `swapAndDeposit` can be exercised on its own.
|
|
1400
1457
|
*/
|
|
1401
1458
|
private runSwap;
|
|
1459
|
+
/**
|
|
1460
|
+
* Throws SWAP_INSUFFICIENT_GAS when the wallet cannot pay for this swap.
|
|
1461
|
+
*
|
|
1462
|
+
* Only the classic rail is ever refused: it is the one where the user sends
|
|
1463
|
+
* the transactions. Call it on a preview quote to warn BEFORE a withdrawal
|
|
1464
|
+
* moves anything — `withdrawAndSwap` repeats it on its own quote, but by
|
|
1465
|
+
* then the funds have already left the agent (ROUT-622).
|
|
1466
|
+
*/
|
|
1467
|
+
checkSwapGas(quote: SwapQuote): Promise<void>;
|
|
1402
1468
|
/**
|
|
1403
1469
|
* The half of the swap deps that only ever talks to the routing API.
|
|
1404
1470
|
*
|
|
@@ -1758,6 +1824,19 @@ declare class OwneySDK {
|
|
|
1758
1824
|
selection: UserPoolSelectionRequest;
|
|
1759
1825
|
agentId?: AgentId;
|
|
1760
1826
|
}): Promise<void>;
|
|
1827
|
+
/**
|
|
1828
|
+
* The pool selection saved on the user's account (ROUT-650), so the Pools
|
|
1829
|
+
* step can show what applies now rather than the defaults. `pairs` and
|
|
1830
|
+
* `assets` say which protocol/chain lists and strategies to read.
|
|
1831
|
+
*/
|
|
1832
|
+
getPoolSelection(params: {
|
|
1833
|
+
pairs: Array<{
|
|
1834
|
+
protocolId: string;
|
|
1835
|
+
chainId: number;
|
|
1836
|
+
}>;
|
|
1837
|
+
assets: Array<"USDC" | "WETH">;
|
|
1838
|
+
agentId?: AgentId;
|
|
1839
|
+
}): Promise<SavedPoolSelection>;
|
|
1761
1840
|
getAccountApy({ agentId, days, tokenSymbol, chainId: scope, }: AccountApyOptions): Promise<OwneyAccountApy | AccountAgentApy>;
|
|
1762
1841
|
/**
|
|
1763
1842
|
* Get transaction history for a specific agent, or all agents.
|
|
@@ -1900,4 +1979,4 @@ type StoredOrder = {
|
|
|
1900
1979
|
*/
|
|
1901
1980
|
declare function listOrders(now?: number): StoredOrder[];
|
|
1902
1981
|
|
|
1903
|
-
export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
|
|
1982
|
+
export { type AccountAgentApy, type AccountApyOptions, type AccountDailyEarnings, type AgentApy, type AgentApyDetails, type AgentBalance, AgentChainIncompatibleError, type AgentEarnings, type AgentHistoryEntry, type AgentHistoryPosition, type AgentId, AgentNotFoundError, type AgentSupportedAsset, type AgentSupportedAssets, type AgentUserProfile, type AgentWithdrawResult, type AgentsApyOptions, type AllocationAgentApy, type AllocationApyOptions, type ApyByChainAndAsset, type ApyCoverage, type ApyHistoryPoint, type Asset, type AssetDailyEarnings, type AvailableAgent, type AvailableAgentsOptions, type AvailablePool, type ConnectionState, type DailyApyDays, type DailyEarningsOptions, type DailyEarningsPoint, type DepositCallback, type DepositOptions, type HistoryAction, type HistoryFilters, type HistoryOptions, type HistoryTransaction, type IAgent, InvalidHistoryCursorError, type LookbackDays, NotConnectedError, type OrgPoolPolicy, type OrgPoolSelection, type OwneyAccountApy, type OwneyAgentApy, type OwneyAgentHistory, type OwneyAllocationApy, type OwneyBalances, type OwneyDepositResult, type OwneyEarnings, OwneyError, type OwneyErrorCode, type OwneyMultiDepositResult, type OwneyPosition, OwneySDK, type OwneySDKConfig, type OwneySIWXConfig, type OwneySupportedChainId, type OwneySupportedChains, type OwneySupportedTokens, type OwneyToken, type OwneyUserProfile, type OwneyWithdrawAllLeg, type OwneyWithdrawAllResult, type OwneyWithdrawResult, type PendingDeposit, type PoolCatalogProtocol, type PoolSelectionStrategy, type RebalanceLog, type SavedPoolSelection, type SwapChainTokens, type SwapDirection, type SwapOrderStatus, type SwapQuote, type SwapQuoteParams, type SwapRail, type SwapStage, type SwapTokenInfo, type SwapTokenSearchResult, type UserPoolSelection, type UserPoolSelectionRequest, type WithdrawOptions, type WithdrawSwapRecord, type WithdrawSwapStatus, clearWithdrawSwap, createOwneySIWX, listPendingDeposits, listOrders as listPendingSwaps, listWithdrawSwaps, saveWithdrawSwap, setOwneyDebug, subscribeWithdrawSwaps, updateWithdrawSwap };
|
package/dist/index.js
CHANGED
|
@@ -483,23 +483,33 @@ function rawPoolApyForChain(entry, chainId, tokenSymbol) {
|
|
|
483
483
|
function historyCoverage(raw) {
|
|
484
484
|
const chains = /* @__PURE__ */ new Map();
|
|
485
485
|
const assets = /* @__PURE__ */ new Map();
|
|
486
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
486
487
|
for (const date of Object.keys(raw.history ?? {}).sort()) {
|
|
487
488
|
void date;
|
|
488
489
|
const seenChains = /* @__PURE__ */ new Set();
|
|
489
490
|
const seenAssets = /* @__PURE__ */ new Set();
|
|
491
|
+
const seenPairs = /* @__PURE__ */ new Map();
|
|
490
492
|
for (const p of (raw.history ?? {})[date].positions ?? []) {
|
|
491
493
|
const balance = p.balance ?? 0;
|
|
492
494
|
const apy = netApy(p.apy_withFee, p.apy, "apy_withFee");
|
|
493
495
|
if (balance <= 0 || typeof apy !== "number") continue;
|
|
494
496
|
seenChains.add(p.chainId);
|
|
495
|
-
if (p.tokenSymbol)
|
|
497
|
+
if (p.tokenSymbol) {
|
|
498
|
+
const asset = p.tokenSymbol.toUpperCase();
|
|
499
|
+
seenAssets.add(asset);
|
|
500
|
+
seenPairs.set(`${p.chainId}:${asset}`, { chainId: p.chainId, asset });
|
|
501
|
+
}
|
|
496
502
|
}
|
|
497
503
|
for (const c of seenChains) chains.set(c, (chains.get(c) ?? 0) + 1);
|
|
498
504
|
for (const a of seenAssets) assets.set(a, (assets.get(a) ?? 0) + 1);
|
|
505
|
+
for (const [key2, pair] of seenPairs) {
|
|
506
|
+
pairs.set(key2, { ...pair, days: (pairs.get(key2)?.days ?? 0) + 1 });
|
|
507
|
+
}
|
|
499
508
|
}
|
|
500
509
|
return {
|
|
501
510
|
chains: [...chains].map(([chainId, days]) => ({ chainId, days })),
|
|
502
|
-
assets: [...assets].map(([asset, days]) => ({ asset, days }))
|
|
511
|
+
assets: [...assets].map(([asset, days]) => ({ asset, days })),
|
|
512
|
+
pairs: [...pairs.values()]
|
|
503
513
|
};
|
|
504
514
|
}
|
|
505
515
|
function mapApyHistory(raw, chainId, tokenSymbol) {
|
|
@@ -544,6 +554,9 @@ function mapEntries(rawEntries, chainId) {
|
|
|
544
554
|
// "Top up wallet" and for slightly less (gas). `Deposit` already exists in
|
|
545
555
|
// the public HistoryAction union, so no consumer type change is needed.
|
|
546
556
|
"Deposit to protocol": "Deposit",
|
|
557
|
+
// Withdrawing from an async vault (Superform) is logged under its own
|
|
558
|
+
// label and paid out later in a separate batch (ROUT-624).
|
|
559
|
+
"Request async withdrawal": "Withdraw",
|
|
547
560
|
Rebalance: "Rebalance"
|
|
548
561
|
};
|
|
549
562
|
void chainId;
|
|
@@ -586,8 +599,9 @@ function mapEntries(rawEntries, chainId) {
|
|
|
586
599
|
];
|
|
587
600
|
}
|
|
588
601
|
const mappedAction = (entry.action ? actionMap[entry.action] : void 0) ?? entry.action;
|
|
602
|
+
const asyncRequest = entry.action === "Request async withdrawal";
|
|
589
603
|
const rawAmount = entry?.positions?.[0]?.amount;
|
|
590
|
-
const hasAmount = mappedAction !== "Withdraw" && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
604
|
+
const hasAmount = (mappedAction !== "Withdraw" || asyncRequest) && typeof rawAmount === "string" && rawAmount !== "" && rawAmount !== "0x" && rawAmount !== "0x0" && rawAmount !== "0";
|
|
591
605
|
const mappedPositions = positions.filter((p) => p.protocol_name).map((p) => ({
|
|
592
606
|
protocol: p.protocol_name,
|
|
593
607
|
pool: p.pool ?? void 0,
|
|
@@ -601,6 +615,7 @@ function mapEntries(rawEntries, chainId) {
|
|
|
601
615
|
newApy: newApy === null ? null : String(newApy),
|
|
602
616
|
oldApy: oldApy === null ? null : String(oldApy),
|
|
603
617
|
...mappedPositions.length ? { positions: mappedPositions } : {},
|
|
618
|
+
...asyncRequest ? { asyncRequest: true } : {},
|
|
604
619
|
transactions: [
|
|
605
620
|
{
|
|
606
621
|
txHashes: entry.transactionHash ? [entry.transactionHash] : [],
|
|
@@ -1241,7 +1256,7 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1241
1256
|
*/
|
|
1242
1257
|
async resolveWithdrawnAmounts(entries, chainId, recipient) {
|
|
1243
1258
|
const withdrawals = entries.filter(
|
|
1244
|
-
(e) => e.action === "Withdraw" && e.transactions[0]?.txHashes[0]
|
|
1259
|
+
(e) => e.action === "Withdraw" && !e.asyncRequest && e.transactions[0]?.txHashes[0]
|
|
1245
1260
|
);
|
|
1246
1261
|
if (withdrawals.length === 0) return;
|
|
1247
1262
|
const client = this.getPublicClient(chainId);
|
|
@@ -1747,6 +1762,44 @@ var ZyfaiAgent = class _ZyfaiAgent {
|
|
|
1747
1762
|
);
|
|
1748
1763
|
}
|
|
1749
1764
|
}
|
|
1765
|
+
/**
|
|
1766
|
+
* Read back what `setPoolSelection` wrote (ROUT-650). Zyfai keeps the saved
|
|
1767
|
+
* pools per protocol/chain and the strategy per asset; both are read for the
|
|
1768
|
+
* pairs and assets asked about. A pair still on autoselect, or one whose
|
|
1769
|
+
* lookup fails, is left out so the caller falls back to its default for it.
|
|
1770
|
+
*/
|
|
1771
|
+
async getPoolSelection(params) {
|
|
1772
|
+
const [pairs, strategies] = await Promise.all([
|
|
1773
|
+
Promise.all(
|
|
1774
|
+
params.pairs.map(async ({ protocolId, chainId }) => {
|
|
1775
|
+
try {
|
|
1776
|
+
const current = await this.sdk.getSelectedPools(
|
|
1777
|
+
protocolId,
|
|
1778
|
+
chainId
|
|
1779
|
+
);
|
|
1780
|
+
if (current.autoselect) return null;
|
|
1781
|
+
return { protocolId, chainId, pools: current.pools ?? [] };
|
|
1782
|
+
} catch {
|
|
1783
|
+
return null;
|
|
1784
|
+
}
|
|
1785
|
+
})
|
|
1786
|
+
),
|
|
1787
|
+
Promise.all(
|
|
1788
|
+
params.assets.map(async (asset) => {
|
|
1789
|
+
try {
|
|
1790
|
+
const current = await this.sdk.getUserDetails(asset);
|
|
1791
|
+
return current.strategy ? { asset, strategy: current.strategy } : null;
|
|
1792
|
+
} catch {
|
|
1793
|
+
return null;
|
|
1794
|
+
}
|
|
1795
|
+
})
|
|
1796
|
+
)
|
|
1797
|
+
]);
|
|
1798
|
+
return {
|
|
1799
|
+
pairs: pairs.filter((value) => value !== null),
|
|
1800
|
+
strategies: strategies.filter((value) => value !== null)
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1750
1803
|
/**
|
|
1751
1804
|
* True when `smartWallet` is the backend-managed pool wallet Zyfai assigned
|
|
1752
1805
|
* to this EOA — the "new wallet" kind that is predeployed on the chains it
|
|
@@ -2854,6 +2907,33 @@ function swapChain(chainId) {
|
|
|
2854
2907
|
return CHAINS[chainId];
|
|
2855
2908
|
}
|
|
2856
2909
|
|
|
2910
|
+
// src/lib/swap/swap.gas-check.ts
|
|
2911
|
+
var CLASSIC_SWAP_GAS = 300000n;
|
|
2912
|
+
var APPROVE_GAS2 = 60000n;
|
|
2913
|
+
var isNative = (address) => address.toLowerCase().startsWith("0xeeee");
|
|
2914
|
+
async function swapGasShortfall(deps, quote) {
|
|
2915
|
+
if (quote.rail !== "classic" || isNative(quote.src.address)) return null;
|
|
2916
|
+
const gas = CLASSIC_SWAP_GAS + APPROVE_GAS2;
|
|
2917
|
+
const [balance, gasPrice] = await Promise.all([
|
|
2918
|
+
deps.readNativeBalance(),
|
|
2919
|
+
deps.getMaxFeePerGas()
|
|
2920
|
+
]);
|
|
2921
|
+
const required = gas * gasPrice;
|
|
2922
|
+
return balance < required ? { chainId: quote.src.chainId, balance, required } : null;
|
|
2923
|
+
}
|
|
2924
|
+
function swapGasError(shortfall, nativeSymbol) {
|
|
2925
|
+
return new OwneyError(
|
|
2926
|
+
"SWAP_INSUFFICIENT_GAS",
|
|
2927
|
+
`This swap needs a little ${nativeSymbol} for network fees, and your wallet has too little. Add some ${nativeSymbol}, or choose a different asset to receive.`,
|
|
2928
|
+
{
|
|
2929
|
+
chainId: shortfall.chainId,
|
|
2930
|
+
symbol: nativeSymbol,
|
|
2931
|
+
balance: shortfall.balance.toString(),
|
|
2932
|
+
required: shortfall.required.toString()
|
|
2933
|
+
}
|
|
2934
|
+
);
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2857
2937
|
// src/lib/swap/swap.arrival.ts
|
|
2858
2938
|
var DEFAULT_TIMEOUT_MS = 18e4;
|
|
2859
2939
|
var DEFAULT_POLL_MS = 4e3;
|
|
@@ -3370,8 +3450,8 @@ async function runClassic(deps, options) {
|
|
|
3370
3450
|
onStage?.("quoting");
|
|
3371
3451
|
debugLog("owney-sdk", "swap: fetching classic calldata");
|
|
3372
3452
|
let { tx } = await deps.api.swapTx(swapTxRequest);
|
|
3373
|
-
const
|
|
3374
|
-
if (!
|
|
3453
|
+
const isNative2 = BigInt(tx.value ?? "0") > 0n;
|
|
3454
|
+
if (!isNative2) {
|
|
3375
3455
|
const needed = amount;
|
|
3376
3456
|
const current = await deps.readAllowance(tx.to);
|
|
3377
3457
|
debugLog("owney-sdk", "swap: allowance", {
|
|
@@ -4448,6 +4528,15 @@ function makeSponsoredCallsCallback(deps) {
|
|
|
4448
4528
|
|
|
4449
4529
|
// src/client.ts
|
|
4450
4530
|
var WALLET_CATCHUP_TIMEOUT_MS = 3e4;
|
|
4531
|
+
function shortfallBalance(error, asked) {
|
|
4532
|
+
if (!(error instanceof OwneyError)) return void 0;
|
|
4533
|
+
if (error.code !== "DEPOSIT_INSUFFICIENT_BALANCE") return void 0;
|
|
4534
|
+
const seen = error.details?.balance;
|
|
4535
|
+
if (typeof seen !== "string") return void 0;
|
|
4536
|
+
const balance = BigInt(seen);
|
|
4537
|
+
if (balance <= 0n || balance >= asked) return void 0;
|
|
4538
|
+
return (asked - balance) * 100n <= asked ? balance : void 0;
|
|
4539
|
+
}
|
|
4451
4540
|
function encodeMultiAgentCursor(map) {
|
|
4452
4541
|
return Buffer.from(JSON.stringify(map), "utf8").toString("base64");
|
|
4453
4542
|
}
|
|
@@ -5457,6 +5546,19 @@ var OwneySDK = class {
|
|
|
5457
5546
|
chain: dstChain,
|
|
5458
5547
|
transport: swapReadTransport(quote.dst.chainId, this.zyfaiRpcUrls)
|
|
5459
5548
|
});
|
|
5549
|
+
const walletPublic = createPublicClient2({
|
|
5550
|
+
chain: srcChain,
|
|
5551
|
+
transport: custom(provider)
|
|
5552
|
+
});
|
|
5553
|
+
const signOnSource = (payload) => signWithChainRetry(
|
|
5554
|
+
walletPublic,
|
|
5555
|
+
wallet,
|
|
5556
|
+
quote.src.chainId,
|
|
5557
|
+
() => wallet.signTypedData({
|
|
5558
|
+
account: state.walletAddress,
|
|
5559
|
+
...payload
|
|
5560
|
+
})
|
|
5561
|
+
);
|
|
5460
5562
|
return {
|
|
5461
5563
|
api: this.swapApi(),
|
|
5462
5564
|
// Native-aware, like readSourceBalance below. Native ETH is never a
|
|
@@ -5497,10 +5599,7 @@ var OwneySDK = class {
|
|
|
5497
5599
|
}
|
|
5498
5600
|
return hash;
|
|
5499
5601
|
},
|
|
5500
|
-
signTypedData:
|
|
5501
|
-
account: state.walletAddress,
|
|
5502
|
-
...typedData
|
|
5503
|
-
}),
|
|
5602
|
+
signTypedData: signOnSource,
|
|
5504
5603
|
// Chain-bound like every other read here: the wallet provider's chain is
|
|
5505
5604
|
// not ours to rely on mid-swap.
|
|
5506
5605
|
readSourceBalance: async () => {
|
|
@@ -5557,10 +5656,7 @@ var OwneySDK = class {
|
|
|
5557
5656
|
spender,
|
|
5558
5657
|
value: amount,
|
|
5559
5658
|
chainId: quote.src.chainId,
|
|
5560
|
-
signTypedData:
|
|
5561
|
-
account: state.walletAddress,
|
|
5562
|
-
...payload
|
|
5563
|
-
})
|
|
5659
|
+
signTypedData: signOnSource
|
|
5564
5660
|
}
|
|
5565
5661
|
),
|
|
5566
5662
|
/**
|
|
@@ -5654,6 +5750,38 @@ var OwneySDK = class {
|
|
|
5654
5750
|
const balance = await this.readTokenBalance(chainId, token);
|
|
5655
5751
|
return (balance < received ? balance : received).toString();
|
|
5656
5752
|
}
|
|
5753
|
+
/**
|
|
5754
|
+
* Deposit a swap's output, retrying once at the balance the deposit saw.
|
|
5755
|
+
*
|
|
5756
|
+
* `settleSwapDepositAmount` approves and THEN reads, but the read and the
|
|
5757
|
+
* deposit's own pre-check can disagree: the approval is confirmed through
|
|
5758
|
+
* the wallet's node, the read goes to a pinned RPC, and gas paid in WETH
|
|
5759
|
+
* (MetaMask offers this to a wallet with no ETH) can land after either.
|
|
5760
|
+
* ROUT-618 failed that way with the settle step in place.
|
|
5761
|
+
*
|
|
5762
|
+
* The pre-check reports the balance it saw, and that is the authority, so
|
|
5763
|
+
* a shortfall is retried once at that figure. Only a small one: a node that
|
|
5764
|
+
* has not caught up can read near zero, and depositing that would leave the
|
|
5765
|
+
* rest of the swap stranded behind a "success".
|
|
5766
|
+
*/
|
|
5767
|
+
async depositSwapOutput(options) {
|
|
5768
|
+
const attempt = (amount) => this.deposit({
|
|
5769
|
+
amount,
|
|
5770
|
+
asset: options.asset,
|
|
5771
|
+
...options.agentId ? { agentId: options.agentId } : {}
|
|
5772
|
+
});
|
|
5773
|
+
try {
|
|
5774
|
+
return {
|
|
5775
|
+
deposit: await attempt(options.amount),
|
|
5776
|
+
deposited: options.amount
|
|
5777
|
+
};
|
|
5778
|
+
} catch (error) {
|
|
5779
|
+
const balance = shortfallBalance(error, BigInt(options.amount));
|
|
5780
|
+
if (balance === void 0) throw error;
|
|
5781
|
+
const deposited = balance.toString();
|
|
5782
|
+
return { deposit: await attempt(deposited), deposited };
|
|
5783
|
+
}
|
|
5784
|
+
}
|
|
5657
5785
|
async walletSeesBalance(chainId, token, amount) {
|
|
5658
5786
|
const provider = this.requireConnectedProvider();
|
|
5659
5787
|
const state = this.requireState();
|
|
@@ -5679,9 +5807,39 @@ var OwneySDK = class {
|
|
|
5679
5807
|
* Runs a quoted swap. A named seam rather than an inline `executeSwap` call
|
|
5680
5808
|
* so the deposit half of `swapAndDeposit` can be exercised on its own.
|
|
5681
5809
|
*/
|
|
5682
|
-
runSwap(quote, options) {
|
|
5810
|
+
async runSwap(quote, options) {
|
|
5811
|
+
await this.checkSwapGas(quote);
|
|
5683
5812
|
return executeSwap(this.buildSwapDeps(quote), { quote, ...options });
|
|
5684
5813
|
}
|
|
5814
|
+
/**
|
|
5815
|
+
* Throws SWAP_INSUFFICIENT_GAS when the wallet cannot pay for this swap.
|
|
5816
|
+
*
|
|
5817
|
+
* Only the classic rail is ever refused: it is the one where the user sends
|
|
5818
|
+
* the transactions. Call it on a preview quote to warn BEFORE a withdrawal
|
|
5819
|
+
* moves anything — `withdrawAndSwap` repeats it on its own quote, but by
|
|
5820
|
+
* then the funds have already left the agent (ROUT-622).
|
|
5821
|
+
*/
|
|
5822
|
+
async checkSwapGas(quote) {
|
|
5823
|
+
const state = this.requireState();
|
|
5824
|
+
const chain = swapChain(quote.src.chainId);
|
|
5825
|
+
if (!chain) return;
|
|
5826
|
+
const pub = createPublicClient2({
|
|
5827
|
+
chain,
|
|
5828
|
+
transport: swapReadTransport(quote.src.chainId, this.zyfaiRpcUrls)
|
|
5829
|
+
});
|
|
5830
|
+
const shortfall = await swapGasShortfall(
|
|
5831
|
+
{
|
|
5832
|
+
readNativeBalance: () => pub.getBalance({ address: state.walletAddress }),
|
|
5833
|
+
// The 1559 ceiling, as the wrap reserve reads it.
|
|
5834
|
+
getMaxFeePerGas: async () => {
|
|
5835
|
+
const fees = await pub.estimateFeesPerGas();
|
|
5836
|
+
return fees.maxFeePerGas ?? pub.getGasPrice();
|
|
5837
|
+
}
|
|
5838
|
+
},
|
|
5839
|
+
quote
|
|
5840
|
+
);
|
|
5841
|
+
if (shortfall) throw swapGasError(shortfall, chain.nativeCurrency.symbol);
|
|
5842
|
+
}
|
|
5685
5843
|
/**
|
|
5686
5844
|
* The half of the swap deps that only ever talks to the routing API.
|
|
5687
5845
|
*
|
|
@@ -5753,8 +5911,15 @@ var OwneySDK = class {
|
|
|
5753
5911
|
);
|
|
5754
5912
|
}
|
|
5755
5913
|
await this.ensureSwapChain(entry.chainId);
|
|
5756
|
-
const
|
|
5757
|
-
|
|
5914
|
+
const token = entry.symbol === "WETH" ? SPONSORED_WETH_BY_CHAIN[entry.chainId] : void 0;
|
|
5915
|
+
const amount = token ? await this.settleSwapDepositAmount(
|
|
5916
|
+
entry.chainId,
|
|
5917
|
+
token,
|
|
5918
|
+
entry.symbol,
|
|
5919
|
+
BigInt(entry.received)
|
|
5920
|
+
) : entry.received;
|
|
5921
|
+
const { deposit } = await this.depositSwapOutput({
|
|
5922
|
+
amount,
|
|
5758
5923
|
asset: entry.symbol,
|
|
5759
5924
|
...entry.agentId ? { agentId: entry.agentId } : {}
|
|
5760
5925
|
});
|
|
@@ -5994,12 +6159,12 @@ var OwneySDK = class {
|
|
|
5994
6159
|
options.to.symbol,
|
|
5995
6160
|
BigInt(swap.received)
|
|
5996
6161
|
);
|
|
5997
|
-
const deposit = await this.
|
|
6162
|
+
const { deposit, deposited } = await this.depositSwapOutput({
|
|
5998
6163
|
amount,
|
|
5999
6164
|
asset: options.to.symbol,
|
|
6000
6165
|
...options.agentId ? { agentId: options.agentId } : {}
|
|
6001
6166
|
});
|
|
6002
|
-
return { swap, deposit, deposited
|
|
6167
|
+
return { swap, deposit, deposited };
|
|
6003
6168
|
} catch (error) {
|
|
6004
6169
|
const pending = {
|
|
6005
6170
|
id: `${quote.dst.chainId}-${options.to.symbol}-${Date.now()}`,
|
|
@@ -6103,6 +6268,7 @@ var OwneySDK = class {
|
|
|
6103
6268
|
walletAddress: state.walletAddress
|
|
6104
6269
|
});
|
|
6105
6270
|
await this.ensureSwapChain(quote.src.chainId);
|
|
6271
|
+
await this.checkSwapGas(quote);
|
|
6106
6272
|
const swap = await executeSwap(this.buildSwapDeps(quote), {
|
|
6107
6273
|
quote,
|
|
6108
6274
|
walletAddress: state.walletAddress,
|
|
@@ -6613,6 +6779,25 @@ var OwneySDK = class {
|
|
|
6613
6779
|
}
|
|
6614
6780
|
await agent.setPoolSelection(params.selection);
|
|
6615
6781
|
}
|
|
6782
|
+
/**
|
|
6783
|
+
* The pool selection saved on the user's account (ROUT-650), so the Pools
|
|
6784
|
+
* step can show what applies now rather than the defaults. `pairs` and
|
|
6785
|
+
* `assets` say which protocol/chain lists and strategies to read.
|
|
6786
|
+
*/
|
|
6787
|
+
async getPoolSelection(params) {
|
|
6788
|
+
await this.ensureAgentsInitialized();
|
|
6789
|
+
const agent = this.getAgent(params.agentId ?? "zyfai");
|
|
6790
|
+
if (!agent.getPoolSelection) {
|
|
6791
|
+
throw new OwneyError(
|
|
6792
|
+
"POOL_SELECTION_UNSUPPORTED",
|
|
6793
|
+
`Agent ${agent.id} does not support pool customization`
|
|
6794
|
+
);
|
|
6795
|
+
}
|
|
6796
|
+
return agent.getPoolSelection({
|
|
6797
|
+
pairs: params.pairs,
|
|
6798
|
+
assets: params.assets
|
|
6799
|
+
});
|
|
6800
|
+
}
|
|
6616
6801
|
async getAccountApy({
|
|
6617
6802
|
agentId,
|
|
6618
6803
|
days,
|