recon-crypto-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/dist/abis/aave-pool.d.ts +174 -0
- package/dist/abis/aave-pool.js +101 -0
- package/dist/abis/aave-pool.js.map +1 -0
- package/dist/abis/aave-ui-pool-data-provider.d.ts +232 -0
- package/dist/abis/aave-ui-pool-data-provider.js +107 -0
- package/dist/abis/aave-ui-pool-data-provider.js.map +1 -0
- package/dist/abis/access-control.d.ts +94 -0
- package/dist/abis/access-control.js +51 -0
- package/dist/abis/access-control.js.map +1 -0
- package/dist/abis/compound-comet.d.ts +120 -0
- package/dist/abis/compound-comet.js +84 -0
- package/dist/abis/compound-comet.js.map +1 -0
- package/dist/abis/eigenlayer-delegation-manager.d.ts +23 -0
- package/dist/abis/eigenlayer-delegation-manager.js +18 -0
- package/dist/abis/eigenlayer-delegation-manager.js.map +1 -0
- package/dist/abis/eigenlayer-strategy-manager.d.ts +53 -0
- package/dist/abis/eigenlayer-strategy-manager.js +47 -0
- package/dist/abis/eigenlayer-strategy-manager.js.map +1 -0
- package/dist/abis/erc20.d.ts +78 -0
- package/dist/abis/erc20.js +10 -0
- package/dist/abis/erc20.js.map +1 -0
- package/dist/abis/lido.d.ts +80 -0
- package/dist/abis/lido.js +60 -0
- package/dist/abis/lido.js.map +1 -0
- package/dist/abis/morpho-blue.d.ts +321 -0
- package/dist/abis/morpho-blue.js +193 -0
- package/dist/abis/morpho-blue.js.map +1 -0
- package/dist/abis/uniswap-pool.d.ts +70 -0
- package/dist/abis/uniswap-pool.js +53 -0
- package/dist/abis/uniswap-pool.js.map +1 -0
- package/dist/abis/uniswap-position-manager.d.ts +71 -0
- package/dist/abis/uniswap-position-manager.js +41 -0
- package/dist/abis/uniswap-position-manager.js.map +1 -0
- package/dist/config/cache.d.ts +12 -0
- package/dist/config/cache.js +12 -0
- package/dist/config/cache.js.map +1 -0
- package/dist/config/chains.d.ts +24 -0
- package/dist/config/chains.js +158 -0
- package/dist/config/chains.js.map +1 -0
- package/dist/config/contracts.d.ts +107 -0
- package/dist/config/contracts.js +123 -0
- package/dist/config/contracts.js.map +1 -0
- package/dist/config/user-config.d.ts +15 -0
- package/dist/config/user-config.js +93 -0
- package/dist/config/user-config.js.map +1 -0
- package/dist/data/apis/etherscan.d.ts +30 -0
- package/dist/data/apis/etherscan.js +109 -0
- package/dist/data/apis/etherscan.js.map +1 -0
- package/dist/data/cache.d.ts +18 -0
- package/dist/data/cache.js +47 -0
- package/dist/data/cache.js.map +1 -0
- package/dist/data/format.d.ts +6 -0
- package/dist/data/format.js +44 -0
- package/dist/data/format.js.map +1 -0
- package/dist/data/prices.d.ts +12 -0
- package/dist/data/prices.js +81 -0
- package/dist/data/prices.js.map +1 -0
- package/dist/data/rpc.d.ts +17 -0
- package/dist/data/rpc.js +68 -0
- package/dist/data/rpc.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +344 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/balances/index.d.ts +20 -0
- package/dist/modules/balances/index.js +49 -0
- package/dist/modules/balances/index.js.map +1 -0
- package/dist/modules/balances/schemas.d.ts +32 -0
- package/dist/modules/balances/schemas.js +21 -0
- package/dist/modules/balances/schemas.js.map +1 -0
- package/dist/modules/bitcoin/index.d.ts +26 -0
- package/dist/modules/bitcoin/index.js +128 -0
- package/dist/modules/bitcoin/index.js.map +1 -0
- package/dist/modules/bitcoin/schemas.d.ts +49 -0
- package/dist/modules/bitcoin/schemas.js +51 -0
- package/dist/modules/bitcoin/schemas.js.map +1 -0
- package/dist/modules/bitcoin/send.d.ts +52 -0
- package/dist/modules/bitcoin/send.js +158 -0
- package/dist/modules/bitcoin/send.js.map +1 -0
- package/dist/modules/bitcoin/utxo.d.ts +99 -0
- package/dist/modules/bitcoin/utxo.js +116 -0
- package/dist/modules/bitcoin/utxo.js.map +1 -0
- package/dist/modules/compound/actions.d.ts +8 -0
- package/dist/modules/compound/actions.js +154 -0
- package/dist/modules/compound/actions.js.map +1 -0
- package/dist/modules/compound/index.d.ts +26 -0
- package/dist/modules/compound/index.js +141 -0
- package/dist/modules/compound/index.js.map +1 -0
- package/dist/modules/compound/schemas.d.ts +95 -0
- package/dist/modules/compound/schemas.js +37 -0
- package/dist/modules/compound/schemas.js.map +1 -0
- package/dist/modules/execution/index.d.ts +51 -0
- package/dist/modules/execution/index.js +271 -0
- package/dist/modules/execution/index.js.map +1 -0
- package/dist/modules/execution/schemas.d.ts +183 -0
- package/dist/modules/execution/schemas.js +88 -0
- package/dist/modules/execution/schemas.js.map +1 -0
- package/dist/modules/feedback/index.d.ts +28 -0
- package/dist/modules/feedback/index.js +161 -0
- package/dist/modules/feedback/index.js.map +1 -0
- package/dist/modules/feedback/rate-limit.d.ts +15 -0
- package/dist/modules/feedback/rate-limit.js +110 -0
- package/dist/modules/feedback/rate-limit.js.map +1 -0
- package/dist/modules/feedback/schemas.d.ts +41 -0
- package/dist/modules/feedback/schemas.js +40 -0
- package/dist/modules/feedback/schemas.js.map +1 -0
- package/dist/modules/morpho/actions.d.ts +8 -0
- package/dist/modules/morpho/actions.js +265 -0
- package/dist/modules/morpho/actions.js.map +1 -0
- package/dist/modules/morpho/index.d.ts +26 -0
- package/dist/modules/morpho/index.js +94 -0
- package/dist/modules/morpho/index.js.map +1 -0
- package/dist/modules/morpho/schemas.d.ts +130 -0
- package/dist/modules/morpho/schemas.js +34 -0
- package/dist/modules/morpho/schemas.js.map +1 -0
- package/dist/modules/portfolio/index.d.ts +3 -0
- package/dist/modules/portfolio/index.js +197 -0
- package/dist/modules/portfolio/index.js.map +1 -0
- package/dist/modules/portfolio/schemas.d.ts +20 -0
- package/dist/modules/portfolio/schemas.js +15 -0
- package/dist/modules/portfolio/schemas.js.map +1 -0
- package/dist/modules/positions/aave.d.ts +22 -0
- package/dist/modules/positions/aave.js +197 -0
- package/dist/modules/positions/aave.js.map +1 -0
- package/dist/modules/positions/actions.d.ts +18 -0
- package/dist/modules/positions/actions.js +205 -0
- package/dist/modules/positions/actions.js.map +1 -0
- package/dist/modules/positions/index.d.ts +37 -0
- package/dist/modules/positions/index.js +59 -0
- package/dist/modules/positions/index.js.map +1 -0
- package/dist/modules/positions/schemas.d.ts +55 -0
- package/dist/modules/positions/schemas.js +25 -0
- package/dist/modules/positions/schemas.js.map +1 -0
- package/dist/modules/positions/uniswap.d.ts +4 -0
- package/dist/modules/positions/uniswap.js +181 -0
- package/dist/modules/positions/uniswap.js.map +1 -0
- package/dist/modules/prices/index.d.ts +19 -0
- package/dist/modules/prices/index.js +22 -0
- package/dist/modules/prices/index.js.map +1 -0
- package/dist/modules/security/index.d.ts +26 -0
- package/dist/modules/security/index.js +13 -0
- package/dist/modules/security/index.js.map +1 -0
- package/dist/modules/security/permissions.d.ts +8 -0
- package/dist/modules/security/permissions.js +96 -0
- package/dist/modules/security/permissions.js.map +1 -0
- package/dist/modules/security/risk-score.d.ts +18 -0
- package/dist/modules/security/risk-score.js +116 -0
- package/dist/modules/security/risk-score.js.map +1 -0
- package/dist/modules/security/schemas.d.ts +31 -0
- package/dist/modules/security/schemas.js +16 -0
- package/dist/modules/security/schemas.js.map +1 -0
- package/dist/modules/security/verification.d.ts +4 -0
- package/dist/modules/security/verification.js +82 -0
- package/dist/modules/security/verification.js.map +1 -0
- package/dist/modules/shared/approval.d.ts +71 -0
- package/dist/modules/shared/approval.js +130 -0
- package/dist/modules/shared/approval.js.map +1 -0
- package/dist/modules/staking/actions.d.ts +22 -0
- package/dist/modules/staking/actions.js +100 -0
- package/dist/modules/staking/actions.js.map +1 -0
- package/dist/modules/staking/eigenlayer.d.ts +14 -0
- package/dist/modules/staking/eigenlayer.js +105 -0
- package/dist/modules/staking/eigenlayer.js.map +1 -0
- package/dist/modules/staking/index.d.ts +24 -0
- package/dist/modules/staking/index.js +59 -0
- package/dist/modules/staking/index.js.map +1 -0
- package/dist/modules/staking/lido.d.ts +14 -0
- package/dist/modules/staking/lido.js +113 -0
- package/dist/modules/staking/lido.js.map +1 -0
- package/dist/modules/staking/schemas.d.ts +34 -0
- package/dist/modules/staking/schemas.js +20 -0
- package/dist/modules/staking/schemas.js.map +1 -0
- package/dist/modules/swap/index.d.ts +47 -0
- package/dist/modules/swap/index.js +376 -0
- package/dist/modules/swap/index.js.map +1 -0
- package/dist/modules/swap/lifi.d.ts +17 -0
- package/dist/modules/swap/lifi.js +44 -0
- package/dist/modules/swap/lifi.js.map +1 -0
- package/dist/modules/swap/oneinch.d.ts +26 -0
- package/dist/modules/swap/oneinch.js +33 -0
- package/dist/modules/swap/oneinch.js.map +1 -0
- package/dist/modules/swap/schemas.d.ts +65 -0
- package/dist/modules/swap/schemas.js +46 -0
- package/dist/modules/swap/schemas.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.js +257 -0
- package/dist/setup.js.map +1 -0
- package/dist/signing/pre-sign-check.d.ts +8 -0
- package/dist/signing/pre-sign-check.js +231 -0
- package/dist/signing/pre-sign-check.js.map +1 -0
- package/dist/signing/session.d.ts +28 -0
- package/dist/signing/session.js +26 -0
- package/dist/signing/session.js.map +1 -0
- package/dist/signing/tx-store.d.ts +29 -0
- package/dist/signing/tx-store.js +85 -0
- package/dist/signing/tx-store.js.map +1 -0
- package/dist/signing/walletconnect.d.ts +33 -0
- package/dist/signing/walletconnect.js +226 -0
- package/dist/signing/walletconnect.js.map +1 -0
- package/dist/types/index.d.ts +222 -0
- package/dist/types/index.js +18 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +134 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { StakingPosition, SupportedChain } from "../../types/index.js";
|
|
2
|
+
/** Lido staking positions across Ethereum (stETH + wstETH) and Arbitrum (wstETH only). */
|
|
3
|
+
export declare function getLidoPositions(wallet: `0x${string}`, chains: SupportedChain[]): Promise<StakingPosition[]>;
|
|
4
|
+
/** Fetch current Lido Ethereum APR from DefiLlama yields. Cached 10 minutes. */
|
|
5
|
+
export declare function getLidoApr(): Promise<number | undefined>;
|
|
6
|
+
/**
|
|
7
|
+
* Rough rewards estimate for Lido — we lack historical balances without an indexer,
|
|
8
|
+
* so we project: rewards ≈ balance × apr × (days / 365).
|
|
9
|
+
*/
|
|
10
|
+
export declare function estimateLidoRewards(currentBalance: StakingPosition, days: number): {
|
|
11
|
+
amount: string;
|
|
12
|
+
valueUsd?: number;
|
|
13
|
+
note: string;
|
|
14
|
+
} | undefined;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { formatUnits } from "viem";
|
|
2
|
+
import { getClient } from "../../data/rpc.js";
|
|
3
|
+
import { cache } from "../../data/cache.js";
|
|
4
|
+
import { CACHE_TTL } from "../../config/cache.js";
|
|
5
|
+
import { CONTRACTS } from "../../config/contracts.js";
|
|
6
|
+
import { stETHAbi, wstETHAbi } from "../../abis/lido.js";
|
|
7
|
+
import { getTokenPrice } from "../../data/prices.js";
|
|
8
|
+
import { makeTokenAmount, round } from "../../data/format.js";
|
|
9
|
+
/** Lido staking positions across Ethereum (stETH + wstETH) and Arbitrum (wstETH only). */
|
|
10
|
+
export async function getLidoPositions(wallet, chains) {
|
|
11
|
+
const positions = [];
|
|
12
|
+
const ethPrice = await getTokenPrice("ethereum", "native");
|
|
13
|
+
for (const chain of chains) {
|
|
14
|
+
const client = getClient(chain);
|
|
15
|
+
if (chain === "ethereum") {
|
|
16
|
+
const stEthAddr = CONTRACTS.ethereum.lido.stETH;
|
|
17
|
+
const wstEthAddr = CONTRACTS.ethereum.lido.wstETH;
|
|
18
|
+
const [stBalance, wstBalance, stPerWst] = await client.multicall({
|
|
19
|
+
contracts: [
|
|
20
|
+
{ address: stEthAddr, abi: stETHAbi, functionName: "balanceOf", args: [wallet] },
|
|
21
|
+
{ address: wstEthAddr, abi: wstETHAbi, functionName: "balanceOf", args: [wallet] },
|
|
22
|
+
{ address: wstEthAddr, abi: wstETHAbi, functionName: "stEthPerToken" },
|
|
23
|
+
],
|
|
24
|
+
allowFailure: false,
|
|
25
|
+
});
|
|
26
|
+
const stEthWei = stBalance;
|
|
27
|
+
const wstEthWei = wstBalance;
|
|
28
|
+
const stPer = stPerWst;
|
|
29
|
+
// Convert wstETH to stETH equivalent (both 18 decimals).
|
|
30
|
+
const wstInStEth = (wstEthWei * stPer) / 10n ** 18n;
|
|
31
|
+
const totalStEthWei = stEthWei + wstInStEth;
|
|
32
|
+
if (totalStEthWei > 0n) {
|
|
33
|
+
const apr = await getLidoApr();
|
|
34
|
+
positions.push({
|
|
35
|
+
protocol: "lido",
|
|
36
|
+
chain,
|
|
37
|
+
stakedAmount: makeTokenAmount(chain, stEthAddr, totalStEthWei, 18, "stETH", ethPrice),
|
|
38
|
+
apr,
|
|
39
|
+
meta: {
|
|
40
|
+
stEthBalance: stEthWei.toString(),
|
|
41
|
+
wstEthBalance: wstEthWei.toString(),
|
|
42
|
+
wstEthAsStEth: wstInStEth.toString(),
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (chain === "arbitrum") {
|
|
48
|
+
const wstEthAddr = CONTRACTS.arbitrum.lido.wstETH;
|
|
49
|
+
// On Arbitrum, wstETH is the only Lido-adjacent token, and stEthPerToken
|
|
50
|
+
// is not available (bridged representation) — we use Ethereum's rate.
|
|
51
|
+
const wstBalance = (await client.readContract({
|
|
52
|
+
address: wstEthAddr,
|
|
53
|
+
abi: wstETHAbi,
|
|
54
|
+
functionName: "balanceOf",
|
|
55
|
+
args: [wallet],
|
|
56
|
+
}));
|
|
57
|
+
if (wstBalance > 0n) {
|
|
58
|
+
const ethClient = getClient("ethereum");
|
|
59
|
+
const stPer = (await ethClient.readContract({
|
|
60
|
+
address: CONTRACTS.ethereum.lido.wstETH,
|
|
61
|
+
abi: wstETHAbi,
|
|
62
|
+
functionName: "stEthPerToken",
|
|
63
|
+
}));
|
|
64
|
+
const wstInStEth = (wstBalance * stPer) / 10n ** 18n;
|
|
65
|
+
const apr = await getLidoApr();
|
|
66
|
+
positions.push({
|
|
67
|
+
protocol: "lido",
|
|
68
|
+
chain,
|
|
69
|
+
stakedAmount: makeTokenAmount(chain, wstEthAddr, wstInStEth, 18, "wstETH (as stETH)", ethPrice),
|
|
70
|
+
apr,
|
|
71
|
+
meta: { wstEthBalance: wstBalance.toString() },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return positions;
|
|
77
|
+
}
|
|
78
|
+
/** Fetch current Lido Ethereum APR from DefiLlama yields. Cached 10 minutes. */
|
|
79
|
+
export async function getLidoApr() {
|
|
80
|
+
return cache.remember("yields:lido-eth", CACHE_TTL.YIELD, async () => {
|
|
81
|
+
try {
|
|
82
|
+
const res = await fetch("https://yields.llama.fi/pools");
|
|
83
|
+
if (!res.ok)
|
|
84
|
+
return undefined;
|
|
85
|
+
const body = (await res.json());
|
|
86
|
+
const pool = body.data.find((p) => p.project === "lido" && p.symbol === "STETH" && p.chain === "Ethereum");
|
|
87
|
+
return pool ? round(pool.apy / 100, 6) : undefined;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Rough rewards estimate for Lido — we lack historical balances without an indexer,
|
|
96
|
+
* so we project: rewards ≈ balance × apr × (days / 365).
|
|
97
|
+
*/
|
|
98
|
+
export function estimateLidoRewards(currentBalance, days) {
|
|
99
|
+
const apr = currentBalance.apr;
|
|
100
|
+
if (!apr)
|
|
101
|
+
return undefined;
|
|
102
|
+
const bal = Number(formatUnits(BigInt(currentBalance.stakedAmount.amount), 18));
|
|
103
|
+
const amount = bal * apr * (days / 365);
|
|
104
|
+
const valueUsd = currentBalance.stakedAmount.priceUsd
|
|
105
|
+
? round(amount * currentBalance.stakedAmount.priceUsd, 2)
|
|
106
|
+
: undefined;
|
|
107
|
+
return {
|
|
108
|
+
amount: amount.toFixed(6),
|
|
109
|
+
valueUsd,
|
|
110
|
+
note: "Estimate based on current APR; actual rewards depend on rebase timing.",
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=lido.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lido.js","sourceRoot":"","sources":["../../../src/modules/staking/lido.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const getStakingPositionsInput: z.ZodObject<{
|
|
3
|
+
wallet: z.ZodString;
|
|
4
|
+
chains: z.ZodOptional<z.ZodArray<z.ZodEnum<[string, ...string[]]>, "many">>;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
wallet: string;
|
|
7
|
+
chains?: string[] | undefined;
|
|
8
|
+
}, {
|
|
9
|
+
wallet: string;
|
|
10
|
+
chains?: string[] | undefined;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const getStakingRewardsInput: z.ZodObject<{
|
|
13
|
+
wallet: z.ZodString;
|
|
14
|
+
period: z.ZodDefault<z.ZodOptional<z.ZodEnum<["7d", "30d", "90d", "1y"]>>>;
|
|
15
|
+
}, "strip", z.ZodTypeAny, {
|
|
16
|
+
wallet: string;
|
|
17
|
+
period: "7d" | "30d" | "90d" | "1y";
|
|
18
|
+
}, {
|
|
19
|
+
wallet: string;
|
|
20
|
+
period?: "7d" | "30d" | "90d" | "1y" | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
export declare const estimateStakingYieldInput: z.ZodObject<{
|
|
23
|
+
protocol: z.ZodEnum<["lido", "eigenlayer"]>;
|
|
24
|
+
amount: z.ZodNumber;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
amount: number;
|
|
27
|
+
protocol: "lido" | "eigenlayer";
|
|
28
|
+
}, {
|
|
29
|
+
amount: number;
|
|
30
|
+
protocol: "lido" | "eigenlayer";
|
|
31
|
+
}>;
|
|
32
|
+
export type GetStakingPositionsArgs = z.infer<typeof getStakingPositionsInput>;
|
|
33
|
+
export type GetStakingRewardsArgs = z.infer<typeof getStakingRewardsInput>;
|
|
34
|
+
export type EstimateStakingYieldArgs = z.infer<typeof estimateStakingYieldInput>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SUPPORTED_CHAINS } from "../../types/index.js";
|
|
3
|
+
const chainEnum = z.enum(SUPPORTED_CHAINS);
|
|
4
|
+
const walletSchema = z.string().regex(/^0x[a-fA-F0-9]{40}$/, "must be a 0x-prefixed EVM address");
|
|
5
|
+
export const getStakingPositionsInput = z.object({
|
|
6
|
+
wallet: walletSchema,
|
|
7
|
+
chains: z.array(chainEnum).optional(),
|
|
8
|
+
});
|
|
9
|
+
export const getStakingRewardsInput = z.object({
|
|
10
|
+
wallet: walletSchema,
|
|
11
|
+
period: z.enum(["7d", "30d", "90d", "1y"]).optional().default("30d"),
|
|
12
|
+
});
|
|
13
|
+
export const estimateStakingYieldInput = z.object({
|
|
14
|
+
protocol: z.enum(["lido", "eigenlayer"]),
|
|
15
|
+
amount: z
|
|
16
|
+
.number()
|
|
17
|
+
.positive()
|
|
18
|
+
.describe("Human-readable decimal amount of the staked asset (ETH for lido, LST for eigenlayer). Example: 1.5 for 1.5 ETH."),
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/modules/staking/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,gBAAoD,CAAC,CAAC;AAC/E,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,qBAAqB,EAAE,mCAAmC,CAAC,CAAC;AAElG,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7C,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACrE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChD,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxC,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,iHAAiH,CAClH;CACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { GetSwapQuoteArgs, PrepareSwapArgs } from "./schemas.js";
|
|
2
|
+
import type { SupportedChain, UnsignedTx } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Reject slippage configurations that are almost certainly user/agent error.
|
|
5
|
+
* The schema already caps at 500 bps (5%); this adds a soft-cap at 100 bps
|
|
6
|
+
* (1%) that requires an explicit ack. MEV sandwich bots target open-slippage
|
|
7
|
+
* txs, so every unnecessary basis point is paid straight to a searcher.
|
|
8
|
+
*/
|
|
9
|
+
export declare function assertSlippageOk(slippageBps: number | undefined, ack: boolean | undefined): void;
|
|
10
|
+
export declare function getSwapQuote(args: GetSwapQuoteArgs): Promise<{
|
|
11
|
+
warning?: string | undefined;
|
|
12
|
+
savingsVsLifi?: {
|
|
13
|
+
source: "1inch";
|
|
14
|
+
outputDeltaPct: number;
|
|
15
|
+
outputDeltaUsd?: number;
|
|
16
|
+
} | undefined;
|
|
17
|
+
bestSource?: "1inch" | "lifi" | "tie" | undefined;
|
|
18
|
+
alternatives?: ({
|
|
19
|
+
source: "1inch";
|
|
20
|
+
toAmountExpected: string;
|
|
21
|
+
toAmountUsd?: number;
|
|
22
|
+
gasEstimate?: number;
|
|
23
|
+
} | {
|
|
24
|
+
source: "1inch";
|
|
25
|
+
error: string;
|
|
26
|
+
})[] | undefined;
|
|
27
|
+
fromChain: string;
|
|
28
|
+
toChain: string;
|
|
29
|
+
fromToken: import("@lifi/types").Token;
|
|
30
|
+
toToken: import("@lifi/types").Token;
|
|
31
|
+
fromAmount: string;
|
|
32
|
+
toAmountMin: string;
|
|
33
|
+
toAmountExpected: string;
|
|
34
|
+
fromAmountUsd: number | undefined;
|
|
35
|
+
toAmountUsd: number | undefined;
|
|
36
|
+
tool: string;
|
|
37
|
+
executionDurationSeconds: number;
|
|
38
|
+
feeCostsUsd: number | undefined;
|
|
39
|
+
gasCostsUsd: number | undefined;
|
|
40
|
+
crossChain: boolean;
|
|
41
|
+
}>;
|
|
42
|
+
export declare function prepareSwap(args: PrepareSwapArgs): Promise<UnsignedTx>;
|
|
43
|
+
export declare function getSwapStatus(args: {
|
|
44
|
+
txHash: string;
|
|
45
|
+
fromChain: SupportedChain;
|
|
46
|
+
toChain: SupportedChain;
|
|
47
|
+
}): Promise<import("@lifi/types").StatusResponse>;
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
import { parseUnits, formatUnits, encodeFunctionData } from "viem";
|
|
2
|
+
import { fetchQuote, fetchStatus } from "./lifi.js";
|
|
3
|
+
import { fetchOneInchQuote } from "./oneinch.js";
|
|
4
|
+
import { getClient } from "../../data/rpc.js";
|
|
5
|
+
import { erc20Abi } from "../../abis/erc20.js";
|
|
6
|
+
import { readUserConfig, resolveOneInchApiKey } from "../../config/user-config.js";
|
|
7
|
+
function sumLifiCostsUsd(items) {
|
|
8
|
+
if (!items || items.length === 0)
|
|
9
|
+
return undefined;
|
|
10
|
+
let total = 0;
|
|
11
|
+
for (const item of items) {
|
|
12
|
+
const stated = item.amountUSD !== undefined ? Number(item.amountUSD) : NaN;
|
|
13
|
+
const rawAmt = item.amount !== undefined ? Number(item.amount) : NaN;
|
|
14
|
+
const priceUsd = item.token?.priceUSD !== undefined ? Number(item.token.priceUSD) : NaN;
|
|
15
|
+
const decimals = item.token?.decimals ?? 18;
|
|
16
|
+
const derived = Number.isFinite(rawAmt) && Number.isFinite(priceUsd)
|
|
17
|
+
? (rawAmt / 10 ** decimals) * priceUsd
|
|
18
|
+
: NaN;
|
|
19
|
+
if (Number.isFinite(derived)) {
|
|
20
|
+
// Both available: trust derived if they disagree wildly (stated is the known-bad
|
|
21
|
+
// source). 10× threshold catches the "raw-units-as-USD" class of bug.
|
|
22
|
+
if (Number.isFinite(stated) && derived > 0 && stated / derived > 10) {
|
|
23
|
+
total += derived;
|
|
24
|
+
}
|
|
25
|
+
else if (Number.isFinite(stated) && stated >= 0) {
|
|
26
|
+
total += stated;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
total += derived;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (Number.isFinite(stated) && stated >= 0) {
|
|
33
|
+
total += stated;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return total;
|
|
37
|
+
}
|
|
38
|
+
/** Resolve ERC-20 decimals (native = 18). */
|
|
39
|
+
async function resolveDecimals(chain, token, fallback) {
|
|
40
|
+
if (token === "native")
|
|
41
|
+
return 18;
|
|
42
|
+
if (fallback !== undefined)
|
|
43
|
+
return fallback;
|
|
44
|
+
try {
|
|
45
|
+
const client = getClient(chain);
|
|
46
|
+
const d = (await client.readContract({
|
|
47
|
+
address: token,
|
|
48
|
+
abi: erc20Abi,
|
|
49
|
+
functionName: "decimals",
|
|
50
|
+
}));
|
|
51
|
+
return Number(d);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return 18;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* On-chain decimals read with no fallback path. Returns undefined for native (no
|
|
59
|
+
* contract to read) and undefined on RPC failure so callers can distinguish "known
|
|
60
|
+
* to match" from "couldn't verify". Used by prepareSwap to cross-check LiFi's
|
|
61
|
+
* reported token metadata before returning signable calldata.
|
|
62
|
+
*/
|
|
63
|
+
async function readOnchainDecimals(chain, token) {
|
|
64
|
+
if (token === "native")
|
|
65
|
+
return undefined;
|
|
66
|
+
try {
|
|
67
|
+
const client = getClient(chain);
|
|
68
|
+
const d = (await client.readContract({
|
|
69
|
+
address: token,
|
|
70
|
+
abi: erc20Abi,
|
|
71
|
+
functionName: "decimals",
|
|
72
|
+
}));
|
|
73
|
+
return Number(d);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reject slippage configurations that are almost certainly user/agent error.
|
|
81
|
+
* The schema already caps at 500 bps (5%); this adds a soft-cap at 100 bps
|
|
82
|
+
* (1%) that requires an explicit ack. MEV sandwich bots target open-slippage
|
|
83
|
+
* txs, so every unnecessary basis point is paid straight to a searcher.
|
|
84
|
+
*/
|
|
85
|
+
export function assertSlippageOk(slippageBps, ack) {
|
|
86
|
+
if (slippageBps === undefined)
|
|
87
|
+
return;
|
|
88
|
+
if (slippageBps > 100 && !ack) {
|
|
89
|
+
throw new Error(`Requested slippage is ${slippageBps} bps (${(slippageBps / 100).toFixed(2)}%). ` +
|
|
90
|
+
`The default cap is 100 bps (1%) because anything higher is almost always a ` +
|
|
91
|
+
`sandwich-bait misconfiguration. If a thin-liquidity route genuinely needs this, ` +
|
|
92
|
+
`retry with \`acknowledgeHighSlippage: true\` and confirm with the user first.`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export async function getSwapQuote(args) {
|
|
96
|
+
assertSlippageOk(args.slippageBps, args.acknowledgeHighSlippage);
|
|
97
|
+
const chain = args.fromChain;
|
|
98
|
+
const toChain = args.toChain;
|
|
99
|
+
const fromDecimals = await resolveDecimals(chain, args.fromToken, args.fromTokenDecimals);
|
|
100
|
+
const fromAmountWei = parseUnits(args.amount, fromDecimals).toString();
|
|
101
|
+
// Intra-chain only: 1inch has no cross-chain aggregator. Skip silently when no
|
|
102
|
+
// API key is configured so users without a 1inch portal account still get LiFi.
|
|
103
|
+
const intraChain = args.fromChain === args.toChain;
|
|
104
|
+
const oneInchApiKey = intraChain ? resolveOneInchApiKey(readUserConfig()) : undefined;
|
|
105
|
+
const [quote, oneInchRaw] = await Promise.all([
|
|
106
|
+
fetchQuote({
|
|
107
|
+
fromChain: chain,
|
|
108
|
+
toChain,
|
|
109
|
+
fromToken: args.fromToken,
|
|
110
|
+
toToken: args.toToken,
|
|
111
|
+
fromAmount: fromAmountWei,
|
|
112
|
+
fromAddress: args.wallet,
|
|
113
|
+
slippage: args.slippageBps !== undefined ? args.slippageBps / 10_000 : undefined,
|
|
114
|
+
}),
|
|
115
|
+
oneInchApiKey
|
|
116
|
+
? fetchOneInchQuote({
|
|
117
|
+
chain,
|
|
118
|
+
fromToken: args.fromToken,
|
|
119
|
+
toToken: args.toToken,
|
|
120
|
+
fromAmount: fromAmountWei,
|
|
121
|
+
apiKey: oneInchApiKey,
|
|
122
|
+
}).catch((err) => ({ __error: err.message }))
|
|
123
|
+
: Promise.resolve(undefined),
|
|
124
|
+
]);
|
|
125
|
+
const fromTokenDecimals = quote.action.fromToken.decimals;
|
|
126
|
+
const toTokenDecimals = quote.action.toToken.decimals;
|
|
127
|
+
const fromPriceUsd = Number(quote.action.fromToken.priceUSD ?? NaN);
|
|
128
|
+
const toPriceUsd = Number(quote.action.toToken.priceUSD ?? NaN);
|
|
129
|
+
const fromAmountFormatted = formatUnits(BigInt(quote.action.fromAmount), fromTokenDecimals);
|
|
130
|
+
const rawToAmount = formatUnits(BigInt(quote.estimate.toAmount), toTokenDecimals);
|
|
131
|
+
const rawToAmountMin = formatUnits(BigInt(quote.estimate.toAmountMin), toTokenDecimals);
|
|
132
|
+
const fromAmountUsd = Number.isFinite(fromPriceUsd)
|
|
133
|
+
? Number(fromAmountFormatted) * fromPriceUsd
|
|
134
|
+
: undefined;
|
|
135
|
+
const statedToAmountUsd = Number.isFinite(toPriceUsd)
|
|
136
|
+
? Number(rawToAmount) * toPriceUsd
|
|
137
|
+
: undefined;
|
|
138
|
+
// Sanity-check the output amount. LiFi has been observed returning toAmount scaled
|
|
139
|
+
// wrong for some aggregator integrations (100 USDC → supposedly 1288 WBTC). When
|
|
140
|
+
// priced out, the implied output USD vastly exceeds the input USD — no rational
|
|
141
|
+
// route pays >10× the input. When that happens, we re-derive the displayed amount
|
|
142
|
+
// from prices and attach a warning so the caller doesn't sign a malformed tx.
|
|
143
|
+
let toAmountExpected = rawToAmount;
|
|
144
|
+
let toAmountMin = rawToAmountMin;
|
|
145
|
+
let toAmountUsd = statedToAmountUsd;
|
|
146
|
+
let warning;
|
|
147
|
+
if (fromAmountUsd !== undefined &&
|
|
148
|
+
statedToAmountUsd !== undefined &&
|
|
149
|
+
fromAmountUsd > 0 &&
|
|
150
|
+
statedToAmountUsd / fromAmountUsd > 10) {
|
|
151
|
+
// Derive what the output *should* be from prices.
|
|
152
|
+
const impliedToAmount = fromAmountUsd / toPriceUsd;
|
|
153
|
+
// Preserve the route's stated slippage ratio when re-deriving the min.
|
|
154
|
+
const rawRatio = Number(rawToAmount) > 0 ? Number(rawToAmountMin) / Number(rawToAmount) : 1;
|
|
155
|
+
toAmountExpected = impliedToAmount.toString();
|
|
156
|
+
toAmountMin = (impliedToAmount * rawRatio).toString();
|
|
157
|
+
toAmountUsd = fromAmountUsd;
|
|
158
|
+
warning =
|
|
159
|
+
`LiFi returned toAmount=${rawToAmount} ${quote.action.toToken.symbol} (~$${statedToAmountUsd.toFixed(2)}) ` +
|
|
160
|
+
`which is >10× the input value ($${fromAmountUsd.toFixed(2)}). Displayed output re-derived from ` +
|
|
161
|
+
`token prices. Do NOT sign a prepared tx using this quote — fetch a fresh one.`;
|
|
162
|
+
}
|
|
163
|
+
// Intra-chain comparison against 1inch. Quote in the same token, so a direct
|
|
164
|
+
// numeric comparison of output amounts is meaningful. USD is derived from the
|
|
165
|
+
// LiFi-provided toToken price (1inch doesn't return priceUSD) so both sides
|
|
166
|
+
// use the same reference price and only the route differs.
|
|
167
|
+
let alternatives;
|
|
168
|
+
let bestSource;
|
|
169
|
+
let savingsVsLifi;
|
|
170
|
+
if (intraChain && oneInchRaw) {
|
|
171
|
+
if ("__error" in oneInchRaw) {
|
|
172
|
+
alternatives = [{ source: "1inch", error: oneInchRaw.__error }];
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
const oiDecimals = oneInchRaw.dstToken?.decimals ?? toTokenDecimals;
|
|
176
|
+
const oiFormatted = formatUnits(BigInt(oneInchRaw.dstAmount), oiDecimals);
|
|
177
|
+
const oiOut = Number(oiFormatted);
|
|
178
|
+
const oiUsd = Number.isFinite(toPriceUsd) ? oiOut * toPriceUsd : undefined;
|
|
179
|
+
alternatives = [
|
|
180
|
+
{
|
|
181
|
+
source: "1inch",
|
|
182
|
+
toAmountExpected: oiFormatted,
|
|
183
|
+
toAmountUsd: oiUsd,
|
|
184
|
+
gasEstimate: oneInchRaw.gas,
|
|
185
|
+
},
|
|
186
|
+
];
|
|
187
|
+
// Compare against the *raw* LiFi toAmount (not the re-derived one). If LiFi's
|
|
188
|
+
// quote was flagged by the >10× sanity check, the raw number is the one the
|
|
189
|
+
// aggregator actually advertised — that's what we're comparing route quality on.
|
|
190
|
+
const lifiOut = Number(rawToAmount);
|
|
191
|
+
if (lifiOut > 0 && oiOut > 0) {
|
|
192
|
+
const delta = (oiOut - lifiOut) / lifiOut;
|
|
193
|
+
if (Math.abs(delta) < 0.0005)
|
|
194
|
+
bestSource = "tie";
|
|
195
|
+
else
|
|
196
|
+
bestSource = delta > 0 ? "1inch" : "lifi";
|
|
197
|
+
savingsVsLifi = {
|
|
198
|
+
source: "1inch",
|
|
199
|
+
outputDeltaPct: delta * 100,
|
|
200
|
+
outputDeltaUsd: Number.isFinite(toPriceUsd) ? (oiOut - lifiOut) * toPriceUsd : undefined,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
fromChain: args.fromChain,
|
|
207
|
+
toChain: args.toChain,
|
|
208
|
+
fromToken: quote.action.fromToken,
|
|
209
|
+
toToken: quote.action.toToken,
|
|
210
|
+
fromAmount: fromAmountFormatted,
|
|
211
|
+
toAmountMin,
|
|
212
|
+
toAmountExpected,
|
|
213
|
+
fromAmountUsd,
|
|
214
|
+
toAmountUsd,
|
|
215
|
+
tool: quote.tool,
|
|
216
|
+
executionDurationSeconds: quote.estimate.executionDuration,
|
|
217
|
+
feeCostsUsd: sumLifiCostsUsd(quote.estimate.feeCosts),
|
|
218
|
+
gasCostsUsd: sumLifiCostsUsd(quote.estimate.gasCosts),
|
|
219
|
+
crossChain: args.fromChain !== args.toChain,
|
|
220
|
+
...(alternatives ? { alternatives } : {}),
|
|
221
|
+
...(bestSource ? { bestSource } : {}),
|
|
222
|
+
...(savingsVsLifi ? { savingsVsLifi } : {}),
|
|
223
|
+
...(warning ? { warning } : {}),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
export async function prepareSwap(args) {
|
|
227
|
+
assertSlippageOk(args.slippageBps, args.acknowledgeHighSlippage);
|
|
228
|
+
const chain = args.fromChain;
|
|
229
|
+
const fromDecimals = await resolveDecimals(chain, args.fromToken, args.fromTokenDecimals);
|
|
230
|
+
const fromAmountWei = parseUnits(args.amount, fromDecimals).toString();
|
|
231
|
+
const quote = await fetchQuote({
|
|
232
|
+
fromChain: chain,
|
|
233
|
+
toChain: args.toChain,
|
|
234
|
+
fromToken: args.fromToken,
|
|
235
|
+
toToken: args.toToken,
|
|
236
|
+
fromAmount: fromAmountWei,
|
|
237
|
+
fromAddress: args.wallet,
|
|
238
|
+
slippage: args.slippageBps !== undefined ? args.slippageBps / 10_000 : undefined,
|
|
239
|
+
});
|
|
240
|
+
const txRequest = quote.transactionRequest;
|
|
241
|
+
if (!txRequest || !txRequest.to || !txRequest.data) {
|
|
242
|
+
throw new Error("LiFi did not return a transactionRequest for this quote.");
|
|
243
|
+
}
|
|
244
|
+
// Cross-check LiFi's reported token decimals against on-chain reads. A mismatch
|
|
245
|
+
// would mean either LiFi has stale metadata or the route targets a token different
|
|
246
|
+
// from what we asked for — in either case, the formatted expectedOut/minOut shown
|
|
247
|
+
// to the user would be wrong, so refuse. Native assets are skipped (no contract).
|
|
248
|
+
const fromToken = args.fromToken;
|
|
249
|
+
const toToken = args.toToken;
|
|
250
|
+
const [fromDecimalsOnchain, toDecimalsOnchain] = await Promise.all([
|
|
251
|
+
readOnchainDecimals(chain, fromToken),
|
|
252
|
+
readOnchainDecimals(args.toChain, toToken),
|
|
253
|
+
]);
|
|
254
|
+
if (fromDecimalsOnchain !== undefined &&
|
|
255
|
+
fromDecimalsOnchain !== quote.action.fromToken.decimals) {
|
|
256
|
+
throw new Error(`Decimals mismatch for fromToken ${quote.action.fromToken.symbol} (${quote.action.fromToken.address}): ` +
|
|
257
|
+
`LiFi reports ${quote.action.fromToken.decimals}, on-chain says ${fromDecimalsOnchain}. ` +
|
|
258
|
+
`Refusing to return calldata.`);
|
|
259
|
+
}
|
|
260
|
+
if (toDecimalsOnchain !== undefined &&
|
|
261
|
+
toDecimalsOnchain !== quote.action.toToken.decimals) {
|
|
262
|
+
throw new Error(`Decimals mismatch for toToken ${quote.action.toToken.symbol} (${quote.action.toToken.address}): ` +
|
|
263
|
+
`LiFi reports ${quote.action.toToken.decimals}, on-chain says ${toDecimalsOnchain}. ` +
|
|
264
|
+
`Refusing to return calldata.`);
|
|
265
|
+
}
|
|
266
|
+
// Sanity-check the quote before returning signable calldata. LiFi has been observed
|
|
267
|
+
// returning toAmount scaled wrong on certain aggregator integrations (e.g. 10 USDC →
|
|
268
|
+
// ~4500 ETH). The calldata embeds the bogus minOut and won't execute, but we refuse
|
|
269
|
+
// up front so the user doesn't waste a signature on a broken quote. Mirrors the
|
|
270
|
+
// warning path in getSwapQuote.
|
|
271
|
+
const fromPriceUsd = Number(quote.action.fromToken.priceUSD ?? NaN);
|
|
272
|
+
const toPriceUsd = Number(quote.action.toToken.priceUSD ?? NaN);
|
|
273
|
+
const fromAmountFormatted = Number(formatUnits(BigInt(quote.action.fromAmount), quote.action.fromToken.decimals));
|
|
274
|
+
const toAmountFormatted = Number(formatUnits(BigInt(quote.estimate.toAmount), quote.action.toToken.decimals));
|
|
275
|
+
if (Number.isFinite(fromPriceUsd) &&
|
|
276
|
+
Number.isFinite(toPriceUsd) &&
|
|
277
|
+
fromPriceUsd > 0 &&
|
|
278
|
+
toPriceUsd > 0) {
|
|
279
|
+
const fromUsd = fromAmountFormatted * fromPriceUsd;
|
|
280
|
+
const toUsd = toAmountFormatted * toPriceUsd;
|
|
281
|
+
if (fromUsd > 0 && toUsd / fromUsd > 10) {
|
|
282
|
+
throw new Error(`LiFi returned a malformed quote: toAmount=${toAmountFormatted} ${quote.action.toToken.symbol} ` +
|
|
283
|
+
`(~$${toUsd.toFixed(2)}) for input ~$${fromUsd.toFixed(2)} (route: ${quote.tool}). ` +
|
|
284
|
+
`Output is >10× the input value, so the calldata is not safe to sign. ` +
|
|
285
|
+
`Re-run get_swap_quote to fetch a fresh route.`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const fromSym = quote.action.fromToken.symbol;
|
|
289
|
+
const toSym = quote.action.toToken.symbol;
|
|
290
|
+
const crossChain = args.fromChain !== args.toChain;
|
|
291
|
+
const description = crossChain
|
|
292
|
+
? `Bridge ${args.amount} ${fromSym} from ${args.fromChain} to ${toSym} on ${args.toChain} via ${quote.tool}`
|
|
293
|
+
: `Swap ${args.amount} ${fromSym} → ${toSym} on ${args.fromChain} via ${quote.tool}`;
|
|
294
|
+
const swapTx = {
|
|
295
|
+
chain,
|
|
296
|
+
to: txRequest.to,
|
|
297
|
+
data: txRequest.data,
|
|
298
|
+
value: txRequest.value ? BigInt(txRequest.value).toString() : "0",
|
|
299
|
+
from: args.wallet,
|
|
300
|
+
description,
|
|
301
|
+
decoded: {
|
|
302
|
+
functionName: "lifi",
|
|
303
|
+
args: {
|
|
304
|
+
tool: quote.tool,
|
|
305
|
+
from: `${args.amount} ${fromSym}`,
|
|
306
|
+
expectedOut: `${formatUnits(BigInt(quote.estimate.toAmount), quote.action.toToken.decimals)} ${toSym}`,
|
|
307
|
+
minOut: `${formatUnits(BigInt(quote.estimate.toAmountMin), quote.action.toToken.decimals)} ${toSym}`,
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
gasEstimate: txRequest.gasLimit ? BigInt(txRequest.gasLimit).toString() : undefined,
|
|
311
|
+
};
|
|
312
|
+
// ERC-20 inputs require an allowance on `approvalAddress` (LiFi Diamond for most
|
|
313
|
+
// routes, but some tools use a different executor). Without this, the swap reverts
|
|
314
|
+
// on the Diamond's transferFrom — Ledger Live shows "Continue" disabled with $0
|
|
315
|
+
// estimated cost because eth_estimateGas fails. Native inputs skip this step.
|
|
316
|
+
if (fromToken !== "native") {
|
|
317
|
+
const approvalAddress = (quote.estimate.approvalAddress ??
|
|
318
|
+
txRequest.to);
|
|
319
|
+
const client = getClient(chain);
|
|
320
|
+
const allowance = (await client.readContract({
|
|
321
|
+
address: fromToken,
|
|
322
|
+
abi: erc20Abi,
|
|
323
|
+
functionName: "allowance",
|
|
324
|
+
args: [args.wallet, approvalAddress],
|
|
325
|
+
}));
|
|
326
|
+
const amountWeiBig = BigInt(fromAmountWei);
|
|
327
|
+
if (allowance < amountWeiBig) {
|
|
328
|
+
const approveTx = {
|
|
329
|
+
chain,
|
|
330
|
+
to: fromToken,
|
|
331
|
+
data: encodeFunctionData({
|
|
332
|
+
abi: erc20Abi,
|
|
333
|
+
functionName: "approve",
|
|
334
|
+
args: [approvalAddress, amountWeiBig],
|
|
335
|
+
}),
|
|
336
|
+
value: "0",
|
|
337
|
+
from: args.wallet,
|
|
338
|
+
description: `Approve ${args.amount} ${fromSym} for ${quote.tool} via LiFi (exact amount)`,
|
|
339
|
+
decoded: {
|
|
340
|
+
functionName: "approve",
|
|
341
|
+
args: { spender: approvalAddress, amount: `${args.amount} ${fromSym}` },
|
|
342
|
+
},
|
|
343
|
+
next: swapTx,
|
|
344
|
+
};
|
|
345
|
+
if (allowance > 0n) {
|
|
346
|
+
// USDT-style reset: tokens like USDT revert on approve(nonzero→nonzero).
|
|
347
|
+
// Chain approve(0) → approve(amount) → swap so we don't silently fail on
|
|
348
|
+
// the first tx of the triple.
|
|
349
|
+
const resetTx = {
|
|
350
|
+
chain,
|
|
351
|
+
to: fromToken,
|
|
352
|
+
data: encodeFunctionData({
|
|
353
|
+
abi: erc20Abi,
|
|
354
|
+
functionName: "approve",
|
|
355
|
+
args: [approvalAddress, 0n],
|
|
356
|
+
}),
|
|
357
|
+
value: "0",
|
|
358
|
+
from: args.wallet,
|
|
359
|
+
description: `Reset ${fromSym} allowance to 0 (required by USDT-style tokens before re-approval)`,
|
|
360
|
+
decoded: {
|
|
361
|
+
functionName: "approve",
|
|
362
|
+
args: { spender: approvalAddress, amount: "0" },
|
|
363
|
+
},
|
|
364
|
+
next: approveTx,
|
|
365
|
+
};
|
|
366
|
+
return resetTx;
|
|
367
|
+
}
|
|
368
|
+
return approveTx;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return swapTx;
|
|
372
|
+
}
|
|
373
|
+
export async function getSwapStatus(args) {
|
|
374
|
+
return fetchStatus(args.txHash, args.fromChain, args.toChain);
|
|
375
|
+
}
|
|
376
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modules/swap/index.ts"],"names":[],"mappings":"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"}
|