@hypurrquant/defi-cli 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +209 -1
- package/dist/index.js.map +1 -1
- package/dist/main.js +211 -2
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6962,7 +6962,11 @@ function registerLP(parent, getOpts, makeExecutor2) {
|
|
|
6962
6962
|
pair: `${p.symbolX}/${p.symbolY}`,
|
|
6963
6963
|
type: "EMISSION",
|
|
6964
6964
|
source: "lb_hooks",
|
|
6965
|
-
stopped: p.stopped
|
|
6965
|
+
stopped: p.stopped,
|
|
6966
|
+
moePerDay: p.moePerDay,
|
|
6967
|
+
aprPercent: p.aprPercent,
|
|
6968
|
+
rangeTvlUsd: p.rangeTvlUsd,
|
|
6969
|
+
isTopPool: p.isTopPool
|
|
6966
6970
|
});
|
|
6967
6971
|
}
|
|
6968
6972
|
}
|
|
@@ -9964,6 +9968,209 @@ function registerBridge(parent, getOpts) {
|
|
|
9964
9968
|
});
|
|
9965
9969
|
}
|
|
9966
9970
|
|
|
9971
|
+
// src/commands/swap.ts
|
|
9972
|
+
var CHAIN_NAMES = {
|
|
9973
|
+
hyperevm: { kyber: "hyperevm", openocean: "hyperevm" },
|
|
9974
|
+
mantle: { openocean: "mantle" }
|
|
9975
|
+
};
|
|
9976
|
+
var KYBER_API = "https://aggregator-api.kyberswap.com";
|
|
9977
|
+
async function kyberGetQuote(chain, tokenIn, tokenOut, amountIn) {
|
|
9978
|
+
const params = new URLSearchParams({ tokenIn, tokenOut, amountIn });
|
|
9979
|
+
const url = `${KYBER_API}/${chain}/api/v1/routes?${params}`;
|
|
9980
|
+
const res = await fetch(url, { headers: { "x-client-id": "defi-cli" } });
|
|
9981
|
+
if (!res.ok) throw new Error(`KyberSwap quote failed: ${res.status} ${await res.text()}`);
|
|
9982
|
+
const json = await res.json();
|
|
9983
|
+
const data = json.data;
|
|
9984
|
+
if (!data?.routeSummary) throw new Error(`KyberSwap: no route found`);
|
|
9985
|
+
return data;
|
|
9986
|
+
}
|
|
9987
|
+
async function kyberBuildTx(chain, routeSummary, sender, recipient, slippageTolerance) {
|
|
9988
|
+
const url = `${KYBER_API}/${chain}/api/v1/route/build`;
|
|
9989
|
+
const res = await fetch(url, {
|
|
9990
|
+
method: "POST",
|
|
9991
|
+
headers: { "Content-Type": "application/json", "x-client-id": "defi-cli" },
|
|
9992
|
+
body: JSON.stringify({ routeSummary, sender, recipient, slippageTolerance })
|
|
9993
|
+
});
|
|
9994
|
+
if (!res.ok) throw new Error(`KyberSwap build failed: ${res.status} ${await res.text()}`);
|
|
9995
|
+
const json = await res.json();
|
|
9996
|
+
const data = json.data;
|
|
9997
|
+
if (!data) throw new Error("KyberSwap: no build data");
|
|
9998
|
+
return {
|
|
9999
|
+
to: String(data.routerAddress),
|
|
10000
|
+
data: String(data.data),
|
|
10001
|
+
value: String(data.value ?? "0x0")
|
|
10002
|
+
};
|
|
10003
|
+
}
|
|
10004
|
+
var OPENOCEAN_API = "https://open-api.openocean.finance/v4";
|
|
10005
|
+
async function openoceanSwap(chain, inTokenAddress, outTokenAddress, amountIn, slippagePct, account) {
|
|
10006
|
+
const params = new URLSearchParams({
|
|
10007
|
+
inTokenAddress,
|
|
10008
|
+
outTokenAddress,
|
|
10009
|
+
amount: amountIn,
|
|
10010
|
+
gasPrice: "0.1",
|
|
10011
|
+
slippage: slippagePct,
|
|
10012
|
+
account
|
|
10013
|
+
});
|
|
10014
|
+
const url = `${OPENOCEAN_API}/${chain}/swap?${params}`;
|
|
10015
|
+
const res = await fetch(url);
|
|
10016
|
+
if (!res.ok) throw new Error(`OpenOcean swap failed: ${res.status} ${await res.text()}`);
|
|
10017
|
+
const json = await res.json();
|
|
10018
|
+
const data = json.data;
|
|
10019
|
+
if (!data) throw new Error("OpenOcean: no swap data");
|
|
10020
|
+
return {
|
|
10021
|
+
to: String(data.to),
|
|
10022
|
+
data: String(data.data),
|
|
10023
|
+
value: String(data.value ?? "0x0"),
|
|
10024
|
+
outAmount: String(data.outAmount ?? "0")
|
|
10025
|
+
};
|
|
10026
|
+
}
|
|
10027
|
+
var LIQD_API = "https://api.liqd.ag/v2";
|
|
10028
|
+
var LIQD_ROUTER = "0x744489ee3d540777a66f2cf297479745e0852f7a";
|
|
10029
|
+
async function liquidSwapRoute(tokenIn, tokenOut, amountIn, slippagePct) {
|
|
10030
|
+
const params = new URLSearchParams({ tokenIn, tokenOut, amountIn, slippage: slippagePct });
|
|
10031
|
+
const url = `${LIQD_API}/route?${params}`;
|
|
10032
|
+
const res = await fetch(url);
|
|
10033
|
+
if (!res.ok) throw new Error(`LiquidSwap route failed: ${res.status} ${await res.text()}`);
|
|
10034
|
+
const json = await res.json();
|
|
10035
|
+
const execution = json.execution;
|
|
10036
|
+
if (!execution) throw new Error("LiquidSwap: no execution data in response");
|
|
10037
|
+
const details = json.details;
|
|
10038
|
+
return {
|
|
10039
|
+
to: String(execution.to ?? LIQD_ROUTER),
|
|
10040
|
+
data: String(execution.calldata),
|
|
10041
|
+
value: String(execution.value ?? "0x0"),
|
|
10042
|
+
outAmount: String(details?.amountOut ?? json.amountOut ?? "0")
|
|
10043
|
+
};
|
|
10044
|
+
}
|
|
10045
|
+
function registerSwap(parent, getOpts, makeExecutor2) {
|
|
10046
|
+
parent.command("swap").description("Swap tokens via DEX aggregator (KyberSwap, OpenOcean, LiquidSwap)").requiredOption("--from <token>", "Input token symbol or address").requiredOption("--to <token>", "Output token symbol or address").requiredOption("--amount <amount>", "Amount of input token in wei").option("--provider <name>", "Aggregator: kyber, openocean, liquid", "kyber").option("--slippage <bps>", "Slippage tolerance in bps", "50").action(async (opts) => {
|
|
10047
|
+
const executor = makeExecutor2();
|
|
10048
|
+
const chainName = parent.opts().chain ?? "hyperevm";
|
|
10049
|
+
const registry = Registry.loadEmbedded();
|
|
10050
|
+
const provider = opts.provider.toLowerCase();
|
|
10051
|
+
const slippageBps = parseInt(opts.slippage, 10);
|
|
10052
|
+
const fromAddr = opts.from.startsWith("0x") ? opts.from : registry.resolveToken(chainName, opts.from).address;
|
|
10053
|
+
const toAddr = opts.to.startsWith("0x") ? opts.to : registry.resolveToken(chainName, opts.to).address;
|
|
10054
|
+
const wallet = process.env["DEFI_WALLET_ADDRESS"] ?? "0x0000000000000000000000000000000000000001";
|
|
10055
|
+
if (provider === "kyber") {
|
|
10056
|
+
const chainNames = CHAIN_NAMES[chainName];
|
|
10057
|
+
if (!chainNames?.kyber) {
|
|
10058
|
+
printOutput({ error: `KyberSwap: unsupported chain '${chainName}'. Supported: hyperevm` }, getOpts());
|
|
10059
|
+
return;
|
|
10060
|
+
}
|
|
10061
|
+
const kyberChain = chainNames.kyber;
|
|
10062
|
+
try {
|
|
10063
|
+
const quoteData = await kyberGetQuote(kyberChain, fromAddr, toAddr, opts.amount);
|
|
10064
|
+
const routeSummary = quoteData.routeSummary;
|
|
10065
|
+
const amountOut = String(routeSummary.amountOut ?? "0");
|
|
10066
|
+
const txData = await kyberBuildTx(
|
|
10067
|
+
kyberChain,
|
|
10068
|
+
routeSummary,
|
|
10069
|
+
wallet,
|
|
10070
|
+
wallet,
|
|
10071
|
+
slippageBps
|
|
10072
|
+
);
|
|
10073
|
+
const tx = {
|
|
10074
|
+
description: `KyberSwap: swap ${opts.amount} of ${fromAddr} -> ${toAddr}`,
|
|
10075
|
+
to: txData.to,
|
|
10076
|
+
data: txData.data,
|
|
10077
|
+
value: txData.value.startsWith("0x") ? BigInt(txData.value) : BigInt(txData.value || 0),
|
|
10078
|
+
approvals: [{ token: fromAddr, spender: txData.to, amount: BigInt(opts.amount) }]
|
|
10079
|
+
};
|
|
10080
|
+
const result = await executor.execute(tx);
|
|
10081
|
+
printOutput({
|
|
10082
|
+
provider: "kyber",
|
|
10083
|
+
chain: kyberChain,
|
|
10084
|
+
from_token: fromAddr,
|
|
10085
|
+
to_token: toAddr,
|
|
10086
|
+
amount_in: opts.amount,
|
|
10087
|
+
amount_out: amountOut,
|
|
10088
|
+
router: txData.to,
|
|
10089
|
+
...result
|
|
10090
|
+
}, getOpts());
|
|
10091
|
+
} catch (e) {
|
|
10092
|
+
printOutput({ error: `KyberSwap error: ${e instanceof Error ? e.message : String(e)}` }, getOpts());
|
|
10093
|
+
}
|
|
10094
|
+
return;
|
|
10095
|
+
}
|
|
10096
|
+
if (provider === "openocean") {
|
|
10097
|
+
const chainNames = CHAIN_NAMES[chainName];
|
|
10098
|
+
if (!chainNames) {
|
|
10099
|
+
printOutput({ error: `OpenOcean: unsupported chain '${chainName}'. Supported: ${Object.keys(CHAIN_NAMES).join(", ")}` }, getOpts());
|
|
10100
|
+
return;
|
|
10101
|
+
}
|
|
10102
|
+
const ooChain = chainNames.openocean;
|
|
10103
|
+
const fromToken = opts.from.startsWith("0x") ? registry.tokens.get(chainName)?.find((t) => t.address.toLowerCase() === opts.from.toLowerCase()) : registry.tokens.get(chainName)?.find((t) => t.symbol.toLowerCase() === opts.from.toLowerCase());
|
|
10104
|
+
const fromDecimals = fromToken?.decimals ?? 18;
|
|
10105
|
+
const humanAmount = (Number(opts.amount) / 10 ** fromDecimals).toString();
|
|
10106
|
+
const slippagePct = (slippageBps / 100).toFixed(2);
|
|
10107
|
+
try {
|
|
10108
|
+
const swap = await openoceanSwap(
|
|
10109
|
+
ooChain,
|
|
10110
|
+
fromAddr,
|
|
10111
|
+
toAddr,
|
|
10112
|
+
humanAmount,
|
|
10113
|
+
slippagePct,
|
|
10114
|
+
wallet
|
|
10115
|
+
);
|
|
10116
|
+
const tx = {
|
|
10117
|
+
description: `OpenOcean: swap ${opts.amount} of ${fromAddr} -> ${toAddr}`,
|
|
10118
|
+
to: swap.to,
|
|
10119
|
+
data: swap.data,
|
|
10120
|
+
value: swap.value.startsWith("0x") ? BigInt(swap.value) : BigInt(swap.value || 0),
|
|
10121
|
+
approvals: [{ token: fromAddr, spender: swap.to, amount: BigInt(opts.amount) }]
|
|
10122
|
+
};
|
|
10123
|
+
const result = await executor.execute(tx);
|
|
10124
|
+
printOutput({
|
|
10125
|
+
provider: "openocean",
|
|
10126
|
+
chain: ooChain,
|
|
10127
|
+
from_token: fromAddr,
|
|
10128
|
+
to_token: toAddr,
|
|
10129
|
+
amount_in: opts.amount,
|
|
10130
|
+
amount_out: swap.outAmount,
|
|
10131
|
+
router: swap.to,
|
|
10132
|
+
...result
|
|
10133
|
+
}, getOpts());
|
|
10134
|
+
} catch (e) {
|
|
10135
|
+
printOutput({ error: `OpenOcean error: ${e instanceof Error ? e.message : String(e)}` }, getOpts());
|
|
10136
|
+
}
|
|
10137
|
+
return;
|
|
10138
|
+
}
|
|
10139
|
+
if (provider === "liquid") {
|
|
10140
|
+
if (chainName !== "hyperevm") {
|
|
10141
|
+
printOutput({ error: `LiquidSwap only supports hyperevm, got '${chainName}'` }, getOpts());
|
|
10142
|
+
return;
|
|
10143
|
+
}
|
|
10144
|
+
const slippagePct = (slippageBps / 100).toFixed(2);
|
|
10145
|
+
try {
|
|
10146
|
+
const route = await liquidSwapRoute(fromAddr, toAddr, opts.amount, slippagePct);
|
|
10147
|
+
const tx = {
|
|
10148
|
+
description: `LiquidSwap: swap ${opts.amount} of ${fromAddr} -> ${toAddr}`,
|
|
10149
|
+
to: route.to,
|
|
10150
|
+
data: route.data,
|
|
10151
|
+
value: route.value.startsWith("0x") ? BigInt(route.value) : BigInt(route.value || 0),
|
|
10152
|
+
approvals: [{ token: fromAddr, spender: route.to, amount: BigInt(opts.amount) }]
|
|
10153
|
+
};
|
|
10154
|
+
const result = await executor.execute(tx);
|
|
10155
|
+
printOutput({
|
|
10156
|
+
provider: "liquid",
|
|
10157
|
+
chain: chainName,
|
|
10158
|
+
from_token: fromAddr,
|
|
10159
|
+
to_token: toAddr,
|
|
10160
|
+
amount_in: opts.amount,
|
|
10161
|
+
amount_out: route.outAmount,
|
|
10162
|
+
router: route.to,
|
|
10163
|
+
...result
|
|
10164
|
+
}, getOpts());
|
|
10165
|
+
} catch (e) {
|
|
10166
|
+
printOutput({ error: `LiquidSwap error: ${e instanceof Error ? e.message : String(e)}` }, getOpts());
|
|
10167
|
+
}
|
|
10168
|
+
return;
|
|
10169
|
+
}
|
|
10170
|
+
printOutput({ error: `Unknown provider '${opts.provider}'. Choose: kyber, openocean, liquid` }, getOpts());
|
|
10171
|
+
});
|
|
10172
|
+
}
|
|
10173
|
+
|
|
9967
10174
|
// src/commands/setup.ts
|
|
9968
10175
|
import pc2 from "picocolors";
|
|
9969
10176
|
import { createInterface } from "readline";
|
|
@@ -10152,6 +10359,7 @@ registerWallet(program, getOutputMode);
|
|
|
10152
10359
|
registerToken(program, getOutputMode, makeExecutor);
|
|
10153
10360
|
registerWhales(program, getOutputMode);
|
|
10154
10361
|
registerBridge(program, getOutputMode);
|
|
10362
|
+
registerSwap(program, getOutputMode, makeExecutor);
|
|
10155
10363
|
registerSetup(program);
|
|
10156
10364
|
export {
|
|
10157
10365
|
program
|