@whiterresearch/litvmswap-aggregator 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +208 -0
- package/dist/abi/AGGFlowEntrypoint.d.ts +190 -0
- package/dist/abi/AGGFlowEntrypoint.js +114 -0
- package/dist/abi/AGGFlowRouter.d.ts +69 -0
- package/dist/abi/AGGFlowRouter.js +46 -0
- package/dist/abi/ERC20.d.ts +127 -0
- package/dist/abi/ERC20.js +96 -0
- package/dist/abi/UniswapV2Pair.d.ts +77 -0
- package/dist/abi/UniswapV2Pair.js +61 -0
- package/dist/abi/index.d.ts +4 -0
- package/dist/abi/index.js +20 -0
- package/dist/builder/opcodes.d.ts +21 -0
- package/dist/builder/opcodes.js +24 -0
- package/dist/builder/programBuilder.d.ts +12 -0
- package/dist/builder/programBuilder.js +99 -0
- package/dist/client.d.ts +90 -0
- package/dist/client.js +123 -0
- package/dist/constants/index.d.ts +67 -0
- package/dist/constants/index.js +168 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +51 -0
- package/dist/quoter/quoter.d.ts +19 -0
- package/dist/quoter/quoter.js +206 -0
- package/dist/swap/swapBuilder.d.ts +15 -0
- package/dist/swap/swapBuilder.js +136 -0
- package/dist/types/index.d.ts +80 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/format.d.ts +18 -0
- package/dist/utils/format.js +51 -0
- package/package.json +56 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LitVMAggregator = void 0;
|
|
4
|
+
const viem_1 = require("viem");
|
|
5
|
+
const index_js_1 = require("./constants/index.js");
|
|
6
|
+
const quoter_js_1 = require("./quoter/quoter.js");
|
|
7
|
+
const swapBuilder_js_1 = require("./swap/swapBuilder.js");
|
|
8
|
+
const index_js_2 = require("./abi/index.js");
|
|
9
|
+
/**
|
|
10
|
+
* Main SDK Client for LitecoinVM (LitVM) DEX Aggregator
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { LitVMAggregator } from '@whiterresearch/litvmswap-aggregator';
|
|
15
|
+
*
|
|
16
|
+
* const aggregator = new LitVMAggregator();
|
|
17
|
+
*
|
|
18
|
+
* // 1. Get best quote across LitVM liquidity pools
|
|
19
|
+
* const quote = await aggregator.getQuote({
|
|
20
|
+
* tokenIn: 'zkLTC',
|
|
21
|
+
* tokenOut: 'ZKUSDC',
|
|
22
|
+
* amountIn: '1.0',
|
|
23
|
+
* slippageTolerancePercent: 0.5,
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // 2. Build ready-to-execute swap transaction
|
|
27
|
+
* const tx = aggregator.buildSwapTx({
|
|
28
|
+
* quote,
|
|
29
|
+
* userAddress: '0x1234...',
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
class LitVMAggregator {
|
|
34
|
+
quoter;
|
|
35
|
+
publicClient;
|
|
36
|
+
defaultFeeConfig;
|
|
37
|
+
constructor(config) {
|
|
38
|
+
this.publicClient =
|
|
39
|
+
config?.publicClient ??
|
|
40
|
+
(0, viem_1.createPublicClient)({
|
|
41
|
+
chain: index_js_1.LitVMChain,
|
|
42
|
+
transport: (0, viem_1.http)(config?.rpcUrl ?? index_js_1.LitVMChain.rpcUrls.default.http[0]),
|
|
43
|
+
});
|
|
44
|
+
this.quoter = new quoter_js_1.LitVMQuoter(this.publicClient);
|
|
45
|
+
this.defaultFeeConfig = config?.defaultFeeConfig;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Fetches best quote and generates execution program across LitVM pools
|
|
49
|
+
*/
|
|
50
|
+
async getQuote(params) {
|
|
51
|
+
return this.quoter.getQuote(params);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Prepares a ready-to-sign transaction object (to, data, value, chainId)
|
|
55
|
+
*/
|
|
56
|
+
buildSwapTx(params) {
|
|
57
|
+
const feeConfig = params.feeConfig ?? this.defaultFeeConfig;
|
|
58
|
+
return swapBuilder_js_1.LitVMSwapBuilder.buildSwapTransaction({
|
|
59
|
+
...params,
|
|
60
|
+
feeConfig,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Checks ERC20 token allowance for a given spender (defaults to Aggregator Entrypoint)
|
|
65
|
+
*/
|
|
66
|
+
async checkAllowance(params) {
|
|
67
|
+
const spender = params.spenderAddress ?? index_js_1.LITVM_ADDRESSES.aggregatorEntrypoint;
|
|
68
|
+
const allowance = await this.publicClient.readContract({
|
|
69
|
+
address: params.tokenAddress,
|
|
70
|
+
abi: index_js_2.ERC20ABI,
|
|
71
|
+
functionName: 'allowance',
|
|
72
|
+
args: [params.ownerAddress, spender],
|
|
73
|
+
});
|
|
74
|
+
return allowance;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Checks if an ERC20 token needs approval for a swap
|
|
78
|
+
*/
|
|
79
|
+
async needsApproval(params) {
|
|
80
|
+
if (params.tokenAddress === viem_1.zeroAddress)
|
|
81
|
+
return false;
|
|
82
|
+
const currentAllowance = await this.checkAllowance(params);
|
|
83
|
+
return currentAllowance < params.amount;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Generates ERC20 approval transaction data
|
|
87
|
+
*/
|
|
88
|
+
buildApproveTx(params) {
|
|
89
|
+
return swapBuilder_js_1.LitVMSwapBuilder.buildApproveTransaction(params.tokenAddress, params.spenderAddress ?? index_js_1.LITVM_ADDRESSES.aggregatorEntrypoint, params.amount);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Resolves token metadata from address or symbol
|
|
93
|
+
*/
|
|
94
|
+
async getToken(addressOrSymbol) {
|
|
95
|
+
return this.quoter.resolveToken(addressOrSymbol);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Returns list of verified tokens on LitecoinVM
|
|
99
|
+
*/
|
|
100
|
+
getKnownTokens() {
|
|
101
|
+
return Object.values(index_js_1.KNOWN_TOKENS);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Directly executes a swap using a Viem WalletClient
|
|
105
|
+
*/
|
|
106
|
+
async executeSwapWithWallet(params) {
|
|
107
|
+
const tx = this.buildSwapTx({
|
|
108
|
+
quote: params.quote,
|
|
109
|
+
userAddress: params.userAddress,
|
|
110
|
+
receiverAddress: params.receiverAddress,
|
|
111
|
+
feeConfig: params.feeConfig,
|
|
112
|
+
});
|
|
113
|
+
const hash = await params.walletClient.sendTransaction({
|
|
114
|
+
account: params.userAddress,
|
|
115
|
+
to: tx.to,
|
|
116
|
+
data: tx.data,
|
|
117
|
+
value: tx.value,
|
|
118
|
+
chain: index_js_1.LitVMChain,
|
|
119
|
+
});
|
|
120
|
+
return hash;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.LitVMAggregator = LitVMAggregator;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Chain } from 'viem';
|
|
2
|
+
export declare const LITECOIN_VM_CHAIN_ID = 4441;
|
|
3
|
+
/**
|
|
4
|
+
* Viem Chain definition for LitecoinVM (LitVM)
|
|
5
|
+
*/
|
|
6
|
+
export declare const LitVMChain: Chain;
|
|
7
|
+
/**
|
|
8
|
+
* Core contract addresses for the Aggregator & Liquidity Pools on LitecoinVM
|
|
9
|
+
*/
|
|
10
|
+
export declare const LITVM_ADDRESSES: {
|
|
11
|
+
chainId: number;
|
|
12
|
+
aggregatorEntrypoint: "0xF664B56933f3cF0d7d69982b5A8eC9101b80059D";
|
|
13
|
+
/** The wrapper, named explicitly. Same address as aggregatorEntrypoint. */
|
|
14
|
+
pointsWrapper: "0xF664B56933f3cF0d7d69982b5A8eC9101b80059D";
|
|
15
|
+
/**
|
|
16
|
+
* The fee-enforcing entrypoint the wrapper forwards to. It requires the
|
|
17
|
+
* protocol fee to go to the DexFeeVault and to be at least MIN_PROTOCOL_FEE_BPS;
|
|
18
|
+
* a swap that does not will revert. Exposed for inspection — route through
|
|
19
|
+
* `aggregatorEntrypoint` so points are still recorded.
|
|
20
|
+
*/
|
|
21
|
+
feeEnforcingEntrypoint: "0x5E19EB2A6BA30892CCe33f93D7Fb24D498512266";
|
|
22
|
+
/**
|
|
23
|
+
* Superseded. The original entrypoint, which took feeCollector and feeBps
|
|
24
|
+
* straight from calldata and enforced neither, so any caller could pay the
|
|
25
|
+
* protocol nothing. The wrapper no longer routes here. Kept only so an
|
|
26
|
+
* integrator pinning this address can see why their swaps changed.
|
|
27
|
+
* @deprecated use `aggregatorEntrypoint`
|
|
28
|
+
*/
|
|
29
|
+
legacyEntrypointNoFeeEnforcement: "0xF69E64804000d28aA695eB5c594B996100fb3B49";
|
|
30
|
+
aggregatorRouter: "0x0624E93350bFfc5B3570589FCae68e2CaBe6c620";
|
|
31
|
+
platformFeeCollector: "0xF2DF37067a8Af0e9ae617c96C887B2FdA8eA3f10";
|
|
32
|
+
wrappedNative: "0x315374AA9b5536037Cc1Efeea2439CCC0913A77e";
|
|
33
|
+
weth: "0x315374AA9b5536037Cc1Efeea2439CCC0913A77e";
|
|
34
|
+
ourV2Factory: "0x4680BCe1632824d30D2F53656dD610736c3e312e";
|
|
35
|
+
ourV2Router: "0xF456737D17C2Bbb348fd4F7D1b000D62A46FB3b5";
|
|
36
|
+
inkyV2Factory: "0x458C5d5B75ccBA22651D2C5b61cB1EA1e0b0f95D";
|
|
37
|
+
v3Factory: "0xde6763a041f8fc94ca2ee5933736f78f6d1a11c5";
|
|
38
|
+
v3Router: "0x60F8A7642F0aeC06cE628224E743326B23Fe5208";
|
|
39
|
+
v3PositionManager: "0x1089f046B597f259BeFDC15Bf9C90E33616BA366";
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Sentinel address for native LTC/ETH
|
|
43
|
+
*/
|
|
44
|
+
/**
|
|
45
|
+
* Minimum protocol fee, in basis points, enforced on-chain by the entrypoint.
|
|
46
|
+
* A swap routed through the entrypoint with a lower fee, or with the fee pointed
|
|
47
|
+
* anywhere other than the DexFeeVault, reverts.
|
|
48
|
+
*/
|
|
49
|
+
export declare const MIN_PROTOCOL_FEE_BPS = 15n;
|
|
50
|
+
export declare const NATIVE_TOKEN_ADDRESS: "0x0000000000000000000000000000000000000000";
|
|
51
|
+
export declare const NATIVE_TOKEN_ALT_ADDRESS: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
52
|
+
export interface TokenInfo {
|
|
53
|
+
address: `0x${string}`;
|
|
54
|
+
symbol: string;
|
|
55
|
+
name: string;
|
|
56
|
+
decimals: number;
|
|
57
|
+
isNative?: boolean;
|
|
58
|
+
logoURI?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Native zkLTC definition
|
|
62
|
+
*/
|
|
63
|
+
export declare const NATIVE_TOKEN: TokenInfo;
|
|
64
|
+
/**
|
|
65
|
+
* Standard tokens deployed on LitecoinVM (Chain ID 4441)
|
|
66
|
+
*/
|
|
67
|
+
export declare const KNOWN_TOKENS: Record<string, TokenInfo>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KNOWN_TOKENS = exports.NATIVE_TOKEN = exports.NATIVE_TOKEN_ALT_ADDRESS = exports.NATIVE_TOKEN_ADDRESS = exports.MIN_PROTOCOL_FEE_BPS = exports.LITVM_ADDRESSES = exports.LitVMChain = exports.LITECOIN_VM_CHAIN_ID = void 0;
|
|
4
|
+
exports.LITECOIN_VM_CHAIN_ID = 4441;
|
|
5
|
+
/**
|
|
6
|
+
* Viem Chain definition for LitecoinVM (LitVM)
|
|
7
|
+
*/
|
|
8
|
+
exports.LitVMChain = {
|
|
9
|
+
id: exports.LITECOIN_VM_CHAIN_ID,
|
|
10
|
+
name: 'LitecoinVM',
|
|
11
|
+
nativeCurrency: {
|
|
12
|
+
name: 'zkLTC',
|
|
13
|
+
symbol: 'zkLTC',
|
|
14
|
+
decimals: 18,
|
|
15
|
+
},
|
|
16
|
+
rpcUrls: {
|
|
17
|
+
default: {
|
|
18
|
+
http: [
|
|
19
|
+
'https://liteforge.rpc.caldera.xyz/http',
|
|
20
|
+
'https://liteforge.rpc.caldera.xyz/infra-partner-http',
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
public: {
|
|
24
|
+
http: [
|
|
25
|
+
'https://liteforge.rpc.caldera.xyz/http',
|
|
26
|
+
'https://liteforge.rpc.caldera.xyz/infra-partner-http',
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
blockExplorers: {
|
|
31
|
+
default: {
|
|
32
|
+
name: 'LitVM Explorer',
|
|
33
|
+
url: 'https://explorer.LitVM.network',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
testnet: true,
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Core contract addresses for the Aggregator & Liquidity Pools on LitecoinVM
|
|
40
|
+
*/
|
|
41
|
+
exports.LITVM_ADDRESSES = {
|
|
42
|
+
chainId: exports.LITECOIN_VM_CHAIN_ID,
|
|
43
|
+
// ── Aggregator contracts ──────────────────────────────────────────────
|
|
44
|
+
// Swaps should go to `aggregatorEntrypoint` — the AGGFlowPointsWrapper. It
|
|
45
|
+
// records Lit Diamonds and applies the NFT staking multiplier, then forwards
|
|
46
|
+
// to the fee-enforcing entrypoint. Calling anything below it skips the points
|
|
47
|
+
// a user has earned.
|
|
48
|
+
aggregatorEntrypoint: '0xF664B56933f3cF0d7d69982b5A8eC9101b80059D',
|
|
49
|
+
/** The wrapper, named explicitly. Same address as aggregatorEntrypoint. */
|
|
50
|
+
pointsWrapper: '0xF664B56933f3cF0d7d69982b5A8eC9101b80059D',
|
|
51
|
+
/**
|
|
52
|
+
* The fee-enforcing entrypoint the wrapper forwards to. It requires the
|
|
53
|
+
* protocol fee to go to the DexFeeVault and to be at least MIN_PROTOCOL_FEE_BPS;
|
|
54
|
+
* a swap that does not will revert. Exposed for inspection — route through
|
|
55
|
+
* `aggregatorEntrypoint` so points are still recorded.
|
|
56
|
+
*/
|
|
57
|
+
feeEnforcingEntrypoint: '0x5E19EB2A6BA30892CCe33f93D7Fb24D498512266',
|
|
58
|
+
/**
|
|
59
|
+
* Superseded. The original entrypoint, which took feeCollector and feeBps
|
|
60
|
+
* straight from calldata and enforced neither, so any caller could pay the
|
|
61
|
+
* protocol nothing. The wrapper no longer routes here. Kept only so an
|
|
62
|
+
* integrator pinning this address can see why their swaps changed.
|
|
63
|
+
* @deprecated use `aggregatorEntrypoint`
|
|
64
|
+
*/
|
|
65
|
+
legacyEntrypointNoFeeEnforcement: '0xF69E64804000d28aA695eB5c594B996100fb3B49',
|
|
66
|
+
aggregatorRouter: '0x0624E93350bFfc5B3570589FCae68e2CaBe6c620',
|
|
67
|
+
platformFeeCollector: '0xF2DF37067a8Af0e9ae617c96C887B2FdA8eA3f10',
|
|
68
|
+
// Wrapped Native (wzkLTC / WETH)
|
|
69
|
+
wrappedNative: '0x315374AA9b5536037Cc1Efeea2439CCC0913A77e',
|
|
70
|
+
weth: '0x315374AA9b5536037Cc1Efeea2439CCC0913A77e',
|
|
71
|
+
// Uniswap V2 Compatible DEXes
|
|
72
|
+
ourV2Factory: '0x4680BCe1632824d30D2F53656dD610736c3e312e',
|
|
73
|
+
ourV2Router: '0xF456737D17C2Bbb348fd4F7D1b000D62A46FB3b5',
|
|
74
|
+
inkyV2Factory: '0x458C5d5B75ccBA22651D2C5b61cB1EA1e0b0f95D',
|
|
75
|
+
// Uniswap V3 Compatible DEXes
|
|
76
|
+
v3Factory: '0xde6763a041f8fc94ca2ee5933736f78f6d1a11c5',
|
|
77
|
+
v3Router: '0x60F8A7642F0aeC06cE628224E743326B23Fe5208',
|
|
78
|
+
v3PositionManager: '0x1089f046B597f259BeFDC15Bf9C90E33616BA366',
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Sentinel address for native LTC/ETH
|
|
82
|
+
*/
|
|
83
|
+
/**
|
|
84
|
+
* Minimum protocol fee, in basis points, enforced on-chain by the entrypoint.
|
|
85
|
+
* A swap routed through the entrypoint with a lower fee, or with the fee pointed
|
|
86
|
+
* anywhere other than the DexFeeVault, reverts.
|
|
87
|
+
*/
|
|
88
|
+
exports.MIN_PROTOCOL_FEE_BPS = 15n; // 0.15%
|
|
89
|
+
exports.NATIVE_TOKEN_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
90
|
+
exports.NATIVE_TOKEN_ALT_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
91
|
+
/**
|
|
92
|
+
* Native zkLTC definition
|
|
93
|
+
*/
|
|
94
|
+
exports.NATIVE_TOKEN = {
|
|
95
|
+
address: exports.NATIVE_TOKEN_ADDRESS,
|
|
96
|
+
symbol: 'zkLTC',
|
|
97
|
+
name: 'Litecoin (zkLTC)',
|
|
98
|
+
decimals: 18,
|
|
99
|
+
isNative: true,
|
|
100
|
+
logoURI: 'https://assets.coingecko.com/coins/images/2/standard/litecoin.png',
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Standard tokens deployed on LitecoinVM (Chain ID 4441)
|
|
104
|
+
*/
|
|
105
|
+
exports.KNOWN_TOKENS = {
|
|
106
|
+
NATIVE: exports.NATIVE_TOKEN,
|
|
107
|
+
WZKLTC: {
|
|
108
|
+
address: '0x315374AA9b5536037Cc1Efeea2439CCC0913A77e',
|
|
109
|
+
symbol: 'wzkLTC',
|
|
110
|
+
name: 'Wrapped zkLTC',
|
|
111
|
+
decimals: 18,
|
|
112
|
+
isNative: false,
|
|
113
|
+
logoURI: 'https://assets.coingecko.com/coins/images/2/standard/litecoin.png',
|
|
114
|
+
},
|
|
115
|
+
ZKUSDC: {
|
|
116
|
+
address: '0xdf69970B2fE416339187aA41D39882e864984CE9',
|
|
117
|
+
symbol: 'ZKUSDC',
|
|
118
|
+
name: 'ZK USD Coin',
|
|
119
|
+
decimals: 18,
|
|
120
|
+
isNative: false,
|
|
121
|
+
logoURI: 'https://assets.coingecko.com/coins/images/53776/standard/usdc.jpg',
|
|
122
|
+
},
|
|
123
|
+
ZKUSDT: {
|
|
124
|
+
address: '0xa338b743Ec494ebB8345f4B6F27ffC902b7EF5Aa',
|
|
125
|
+
symbol: 'ZKUSDT',
|
|
126
|
+
name: 'ZK Tether USD',
|
|
127
|
+
decimals: 18,
|
|
128
|
+
isNative: false,
|
|
129
|
+
logoURI: 'https://assets.coingecko.com/coins/images/53705/standard/usdt0.jpg',
|
|
130
|
+
},
|
|
131
|
+
LETH: {
|
|
132
|
+
address: '0xDF474006aa807598B616500d146FfF661d644138',
|
|
133
|
+
symbol: 'LETH',
|
|
134
|
+
name: 'LitVM Ethereum',
|
|
135
|
+
decimals: 18,
|
|
136
|
+
isNative: false,
|
|
137
|
+
logoURI: 'https://assets.coingecko.com/coins/images/279/standard/ethereum.png',
|
|
138
|
+
},
|
|
139
|
+
ZKBTC: {
|
|
140
|
+
address: '0xca4914407868bc37ccbE324cA149DD475d39A2Bf',
|
|
141
|
+
symbol: 'ZKBTC',
|
|
142
|
+
name: 'ZK Bitcoin',
|
|
143
|
+
decimals: 18,
|
|
144
|
+
isNative: false,
|
|
145
|
+
logoURI: 'https://assets.coingecko.com/coins/images/1/standard/bitcoin.png',
|
|
146
|
+
},
|
|
147
|
+
LITVMSWAP: {
|
|
148
|
+
address: '0xCa4c7EdB398684cB4C5B3fD0cc6ced30b5a5f4d3',
|
|
149
|
+
symbol: 'LitVMSwap',
|
|
150
|
+
name: 'LitVMSwap Token',
|
|
151
|
+
decimals: 18,
|
|
152
|
+
isNative: false,
|
|
153
|
+
},
|
|
154
|
+
LXRP: {
|
|
155
|
+
address: '0xfdf5cD6452EDC340e67cd16db6A9D74aaa4f81a3',
|
|
156
|
+
symbol: 'LXRP',
|
|
157
|
+
name: 'LitVM XRP',
|
|
158
|
+
decimals: 18,
|
|
159
|
+
isNative: false,
|
|
160
|
+
},
|
|
161
|
+
BRBNB: {
|
|
162
|
+
address: '0x58B6CD7891cd0A682226E25607b958a6479195A6',
|
|
163
|
+
symbol: 'brBNB',
|
|
164
|
+
name: 'Bridged BNB',
|
|
165
|
+
decimals: 18,
|
|
166
|
+
isNative: false,
|
|
167
|
+
},
|
|
168
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { LitVMAggregator, type LitVMAggregatorConfig } from './client.js';
|
|
2
|
+
export { LitVMQuoter } from './quoter/quoter.js';
|
|
3
|
+
export { LitVMSwapBuilder } from './swap/swapBuilder.js';
|
|
4
|
+
export { buildAggregatorProgram, addressToBytes } from './builder/programBuilder.js';
|
|
5
|
+
export { OPCODES, POOL_TYPES, WRAP_FLAGS } from './builder/opcodes.js';
|
|
6
|
+
export { LITECOIN_VM_CHAIN_ID, LitVMChain, LITVM_ADDRESSES, MIN_PROTOCOL_FEE_BPS, NATIVE_TOKEN_ADDRESS, NATIVE_TOKEN_ALT_ADDRESS, NATIVE_TOKEN, KNOWN_TOKENS, type TokenInfo, } from './constants/index.js';
|
|
7
|
+
export type { PoolType, RouteLeg, QuoteParams, QuoteResult, FeeConfig, BuildSwapTxParams, PreparedTransaction, SwapIntent, FeeCollection, } from './types/index.js';
|
|
8
|
+
export { toBigIntAmount, formatTokenAmount, calculateMinAmountOut, calculatePriceImpact, } from './utils/format.js';
|
|
9
|
+
export * from './abi/index.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.calculatePriceImpact = exports.calculateMinAmountOut = exports.formatTokenAmount = exports.toBigIntAmount = exports.KNOWN_TOKENS = exports.NATIVE_TOKEN = exports.NATIVE_TOKEN_ALT_ADDRESS = exports.NATIVE_TOKEN_ADDRESS = exports.MIN_PROTOCOL_FEE_BPS = exports.LITVM_ADDRESSES = exports.LitVMChain = exports.LITECOIN_VM_CHAIN_ID = exports.WRAP_FLAGS = exports.POOL_TYPES = exports.OPCODES = exports.addressToBytes = exports.buildAggregatorProgram = exports.LitVMSwapBuilder = exports.LitVMQuoter = exports.LitVMAggregator = void 0;
|
|
18
|
+
// Main Client
|
|
19
|
+
var client_js_1 = require("./client.js");
|
|
20
|
+
Object.defineProperty(exports, "LitVMAggregator", { enumerable: true, get: function () { return client_js_1.LitVMAggregator; } });
|
|
21
|
+
// Quoter & Router
|
|
22
|
+
var quoter_js_1 = require("./quoter/quoter.js");
|
|
23
|
+
Object.defineProperty(exports, "LitVMQuoter", { enumerable: true, get: function () { return quoter_js_1.LitVMQuoter; } });
|
|
24
|
+
// Swap & Program Builders
|
|
25
|
+
var swapBuilder_js_1 = require("./swap/swapBuilder.js");
|
|
26
|
+
Object.defineProperty(exports, "LitVMSwapBuilder", { enumerable: true, get: function () { return swapBuilder_js_1.LitVMSwapBuilder; } });
|
|
27
|
+
var programBuilder_js_1 = require("./builder/programBuilder.js");
|
|
28
|
+
Object.defineProperty(exports, "buildAggregatorProgram", { enumerable: true, get: function () { return programBuilder_js_1.buildAggregatorProgram; } });
|
|
29
|
+
Object.defineProperty(exports, "addressToBytes", { enumerable: true, get: function () { return programBuilder_js_1.addressToBytes; } });
|
|
30
|
+
var opcodes_js_1 = require("./builder/opcodes.js");
|
|
31
|
+
Object.defineProperty(exports, "OPCODES", { enumerable: true, get: function () { return opcodes_js_1.OPCODES; } });
|
|
32
|
+
Object.defineProperty(exports, "POOL_TYPES", { enumerable: true, get: function () { return opcodes_js_1.POOL_TYPES; } });
|
|
33
|
+
Object.defineProperty(exports, "WRAP_FLAGS", { enumerable: true, get: function () { return opcodes_js_1.WRAP_FLAGS; } });
|
|
34
|
+
// Constants & Chain Details
|
|
35
|
+
var index_js_1 = require("./constants/index.js");
|
|
36
|
+
Object.defineProperty(exports, "LITECOIN_VM_CHAIN_ID", { enumerable: true, get: function () { return index_js_1.LITECOIN_VM_CHAIN_ID; } });
|
|
37
|
+
Object.defineProperty(exports, "LitVMChain", { enumerable: true, get: function () { return index_js_1.LitVMChain; } });
|
|
38
|
+
Object.defineProperty(exports, "LITVM_ADDRESSES", { enumerable: true, get: function () { return index_js_1.LITVM_ADDRESSES; } });
|
|
39
|
+
Object.defineProperty(exports, "MIN_PROTOCOL_FEE_BPS", { enumerable: true, get: function () { return index_js_1.MIN_PROTOCOL_FEE_BPS; } });
|
|
40
|
+
Object.defineProperty(exports, "NATIVE_TOKEN_ADDRESS", { enumerable: true, get: function () { return index_js_1.NATIVE_TOKEN_ADDRESS; } });
|
|
41
|
+
Object.defineProperty(exports, "NATIVE_TOKEN_ALT_ADDRESS", { enumerable: true, get: function () { return index_js_1.NATIVE_TOKEN_ALT_ADDRESS; } });
|
|
42
|
+
Object.defineProperty(exports, "NATIVE_TOKEN", { enumerable: true, get: function () { return index_js_1.NATIVE_TOKEN; } });
|
|
43
|
+
Object.defineProperty(exports, "KNOWN_TOKENS", { enumerable: true, get: function () { return index_js_1.KNOWN_TOKENS; } });
|
|
44
|
+
// Math & Format Utilities
|
|
45
|
+
var format_js_1 = require("./utils/format.js");
|
|
46
|
+
Object.defineProperty(exports, "toBigIntAmount", { enumerable: true, get: function () { return format_js_1.toBigIntAmount; } });
|
|
47
|
+
Object.defineProperty(exports, "formatTokenAmount", { enumerable: true, get: function () { return format_js_1.formatTokenAmount; } });
|
|
48
|
+
Object.defineProperty(exports, "calculateMinAmountOut", { enumerable: true, get: function () { return format_js_1.calculateMinAmountOut; } });
|
|
49
|
+
Object.defineProperty(exports, "calculatePriceImpact", { enumerable: true, get: function () { return format_js_1.calculatePriceImpact; } });
|
|
50
|
+
// ABIs
|
|
51
|
+
__exportStar(require("./abi/index.js"), exports);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type PublicClient } from 'viem';
|
|
2
|
+
import { type TokenInfo } from '../constants/index.js';
|
|
3
|
+
import type { QuoteParams, QuoteResult } from '../types/index.js';
|
|
4
|
+
export declare class LitVMQuoter {
|
|
5
|
+
private client;
|
|
6
|
+
constructor(customClient?: PublicClient);
|
|
7
|
+
/**
|
|
8
|
+
* Resolves token metadata from address or symbol
|
|
9
|
+
*/
|
|
10
|
+
resolveToken(addressOrSymbol: string): Promise<TokenInfo>;
|
|
11
|
+
/**
|
|
12
|
+
* Fetches best quote and generates execution program across LitVM pools
|
|
13
|
+
*/
|
|
14
|
+
getQuote(params: QuoteParams): Promise<QuoteResult>;
|
|
15
|
+
/**
|
|
16
|
+
* Helper: Quotes a Uniswap V2 pair
|
|
17
|
+
*/
|
|
18
|
+
private quoteV2Pool;
|
|
19
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LitVMQuoter = void 0;
|
|
4
|
+
const viem_1 = require("viem");
|
|
5
|
+
const index_js_1 = require("../constants/index.js");
|
|
6
|
+
const index_js_2 = require("../abi/index.js");
|
|
7
|
+
const programBuilder_js_1 = require("../builder/programBuilder.js");
|
|
8
|
+
const format_js_1 = require("../utils/format.js");
|
|
9
|
+
class LitVMQuoter {
|
|
10
|
+
client;
|
|
11
|
+
constructor(customClient) {
|
|
12
|
+
this.client =
|
|
13
|
+
customClient ??
|
|
14
|
+
(0, viem_1.createPublicClient)({
|
|
15
|
+
chain: index_js_1.LitVMChain,
|
|
16
|
+
transport: (0, viem_1.http)(index_js_1.LitVMChain.rpcUrls.default.http[0]),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolves token metadata from address or symbol
|
|
21
|
+
*/
|
|
22
|
+
async resolveToken(addressOrSymbol) {
|
|
23
|
+
const query = addressOrSymbol.trim();
|
|
24
|
+
// Check known native tokens
|
|
25
|
+
if (query === viem_1.zeroAddress ||
|
|
26
|
+
query.toLowerCase() === index_js_1.NATIVE_TOKEN_ALT_ADDRESS.toLowerCase() ||
|
|
27
|
+
query.toUpperCase() === 'ETH' ||
|
|
28
|
+
query.toUpperCase() === 'LTC' ||
|
|
29
|
+
query.toUpperCase() === 'ZKLTC') {
|
|
30
|
+
return index_js_1.NATIVE_TOKEN;
|
|
31
|
+
}
|
|
32
|
+
// Check predefined list
|
|
33
|
+
const found = Object.values(index_js_1.KNOWN_TOKENS).find((t) => t.address.toLowerCase() === query.toLowerCase() ||
|
|
34
|
+
t.symbol.toUpperCase() === query.toUpperCase());
|
|
35
|
+
if (found)
|
|
36
|
+
return found;
|
|
37
|
+
// Fetch ERC-20 on-chain details
|
|
38
|
+
const tokenAddr = query;
|
|
39
|
+
const [decimals, symbol, name] = await Promise.all([
|
|
40
|
+
this.client.readContract({
|
|
41
|
+
address: tokenAddr,
|
|
42
|
+
abi: index_js_2.ERC20ABI,
|
|
43
|
+
functionName: 'decimals',
|
|
44
|
+
}),
|
|
45
|
+
this.client.readContract({
|
|
46
|
+
address: tokenAddr,
|
|
47
|
+
abi: index_js_2.ERC20ABI,
|
|
48
|
+
functionName: 'symbol',
|
|
49
|
+
}),
|
|
50
|
+
this.client.readContract({
|
|
51
|
+
address: tokenAddr,
|
|
52
|
+
abi: index_js_2.ERC20ABI,
|
|
53
|
+
functionName: 'name',
|
|
54
|
+
}),
|
|
55
|
+
]);
|
|
56
|
+
return {
|
|
57
|
+
address: tokenAddr,
|
|
58
|
+
symbol,
|
|
59
|
+
name,
|
|
60
|
+
decimals: Number(decimals),
|
|
61
|
+
isNative: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Fetches best quote and generates execution program across LitVM pools
|
|
66
|
+
*/
|
|
67
|
+
async getQuote(params) {
|
|
68
|
+
const fromToken = await this.resolveToken(params.tokenIn);
|
|
69
|
+
const toToken = await this.resolveToken(params.tokenOut);
|
|
70
|
+
if (fromToken.address.toLowerCase() === toToken.address.toLowerCase() && fromToken.isNative === toToken.isNative) {
|
|
71
|
+
throw new Error('Cannot swap a token to itself');
|
|
72
|
+
}
|
|
73
|
+
const amountIn = (0, format_js_1.toBigIntAmount)(params.amountIn, fromToken.decimals);
|
|
74
|
+
if (amountIn <= 0n) {
|
|
75
|
+
throw new Error('Amount in must be greater than 0');
|
|
76
|
+
}
|
|
77
|
+
const slippage = params.slippageTolerancePercent ?? 0.5;
|
|
78
|
+
// Handle Wrap / Unwrap directly
|
|
79
|
+
const isWrap = fromToken.isNative && toToken.address.toLowerCase() === index_js_1.LITVM_ADDRESSES.weth.toLowerCase();
|
|
80
|
+
const isUnwrap = fromToken.address.toLowerCase() === index_js_1.LITVM_ADDRESSES.weth.toLowerCase() && toToken.isNative;
|
|
81
|
+
if (isWrap || isUnwrap) {
|
|
82
|
+
const amountOut = amountIn; // 1:1 wrap/unwrap
|
|
83
|
+
const route = {
|
|
84
|
+
dexName: isWrap ? 'NativeWrap' : 'NativeUnwrap',
|
|
85
|
+
poolType: 'wrap',
|
|
86
|
+
poolAddress: index_js_1.LITVM_ADDRESSES.weth,
|
|
87
|
+
tokenIn: fromToken.address,
|
|
88
|
+
tokenOut: toToken.address,
|
|
89
|
+
};
|
|
90
|
+
return {
|
|
91
|
+
tokenIn: fromToken,
|
|
92
|
+
tokenOut: toToken,
|
|
93
|
+
amountIn,
|
|
94
|
+
amountInFormatted: (0, format_js_1.formatTokenAmount)(amountIn, fromToken.decimals),
|
|
95
|
+
expectedAmountOut: amountOut,
|
|
96
|
+
expectedAmountOutFormatted: (0, format_js_1.formatTokenAmount)(amountOut, toToken.decimals),
|
|
97
|
+
minAmountOut: amountOut,
|
|
98
|
+
minAmountOutFormatted: (0, format_js_1.formatTokenAmount)(amountOut, toToken.decimals),
|
|
99
|
+
priceImpactPercent: 0,
|
|
100
|
+
executionPrice: 1,
|
|
101
|
+
route,
|
|
102
|
+
program: '0x',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// Resolve intermediate ERC20 addresses (if native, route via wzkLTC)
|
|
106
|
+
const tokenInAddr = fromToken.isNative ? index_js_1.LITVM_ADDRESSES.weth : fromToken.address;
|
|
107
|
+
const tokenOutAddr = toToken.isNative ? index_js_1.LITVM_ADDRESSES.weth : toToken.address;
|
|
108
|
+
const candidates = [];
|
|
109
|
+
// 1. Query OurV2 Factory
|
|
110
|
+
const ourV2Candidate = await this.quoteV2Pool(index_js_1.LITVM_ADDRESSES.ourV2Factory, 'OurV2', tokenInAddr, tokenOutAddr, amountIn, 3000 // 0.3% fee
|
|
111
|
+
);
|
|
112
|
+
if (ourV2Candidate)
|
|
113
|
+
candidates.push(ourV2Candidate);
|
|
114
|
+
// 2. Query InkyV2 Factory
|
|
115
|
+
const inkyV2Candidate = await this.quoteV2Pool(index_js_1.LITVM_ADDRESSES.inkyV2Factory, 'InkyV2', tokenInAddr, tokenOutAddr, amountIn, 3000);
|
|
116
|
+
if (inkyV2Candidate)
|
|
117
|
+
candidates.push(inkyV2Candidate);
|
|
118
|
+
if (candidates.length === 0) {
|
|
119
|
+
throw new Error(`No active liquidity pools found between ${fromToken.symbol} and ${toToken.symbol} on LitecoinVM`);
|
|
120
|
+
}
|
|
121
|
+
// Select candidate with the best amountOut
|
|
122
|
+
const best = candidates.reduce((a, b) => (a.amountOut > b.amountOut ? a : b));
|
|
123
|
+
const route = {
|
|
124
|
+
dexName: best.dexName,
|
|
125
|
+
poolType: best.poolType,
|
|
126
|
+
poolAddress: best.poolAddress,
|
|
127
|
+
tokenIn: fromToken.address,
|
|
128
|
+
tokenOut: toToken.address,
|
|
129
|
+
fee: best.fee,
|
|
130
|
+
};
|
|
131
|
+
// Compile bytecode program for AGGFlow
|
|
132
|
+
const program = (0, programBuilder_js_1.buildAggregatorProgram)(fromToken, toToken, route, index_js_1.LITVM_ADDRESSES.weth);
|
|
133
|
+
const minAmountOut = (0, format_js_1.calculateMinAmountOut)(best.amountOut, slippage);
|
|
134
|
+
const priceImpact = best.reserveIn && best.reserveOut
|
|
135
|
+
? (0, format_js_1.calculatePriceImpact)(amountIn, best.amountOut, best.reserveIn, best.reserveOut)
|
|
136
|
+
: 0;
|
|
137
|
+
const inUnits = Number((0, format_js_1.formatTokenAmount)(amountIn, fromToken.decimals, 6));
|
|
138
|
+
const outUnits = Number((0, format_js_1.formatTokenAmount)(best.amountOut, toToken.decimals, 6));
|
|
139
|
+
const executionPrice = inUnits > 0 ? outUnits / inUnits : 0;
|
|
140
|
+
return {
|
|
141
|
+
tokenIn: fromToken,
|
|
142
|
+
tokenOut: toToken,
|
|
143
|
+
amountIn,
|
|
144
|
+
amountInFormatted: (0, format_js_1.formatTokenAmount)(amountIn, fromToken.decimals),
|
|
145
|
+
expectedAmountOut: best.amountOut,
|
|
146
|
+
expectedAmountOutFormatted: (0, format_js_1.formatTokenAmount)(best.amountOut, toToken.decimals),
|
|
147
|
+
minAmountOut,
|
|
148
|
+
minAmountOutFormatted: (0, format_js_1.formatTokenAmount)(minAmountOut, toToken.decimals),
|
|
149
|
+
priceImpactPercent: priceImpact,
|
|
150
|
+
executionPrice,
|
|
151
|
+
route,
|
|
152
|
+
program,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Helper: Quotes a Uniswap V2 pair
|
|
157
|
+
*/
|
|
158
|
+
async quoteV2Pool(factory, dexName, tokenA, tokenB, amountIn, fee) {
|
|
159
|
+
try {
|
|
160
|
+
const pair = await this.client.readContract({
|
|
161
|
+
address: factory,
|
|
162
|
+
abi: index_js_2.UniswapV2FactoryABI,
|
|
163
|
+
functionName: 'getPair',
|
|
164
|
+
args: [tokenA, tokenB],
|
|
165
|
+
});
|
|
166
|
+
if (!pair || pair === viem_1.zeroAddress)
|
|
167
|
+
return null;
|
|
168
|
+
const [reserves, token0] = await Promise.all([
|
|
169
|
+
this.client.readContract({
|
|
170
|
+
address: pair,
|
|
171
|
+
abi: index_js_2.UniswapV2PairABI,
|
|
172
|
+
functionName: 'getReserves',
|
|
173
|
+
}),
|
|
174
|
+
this.client.readContract({
|
|
175
|
+
address: pair,
|
|
176
|
+
abi: index_js_2.UniswapV2PairABI,
|
|
177
|
+
functionName: 'token0',
|
|
178
|
+
}),
|
|
179
|
+
]);
|
|
180
|
+
const isToken0 = tokenA.toLowerCase() === token0.toLowerCase();
|
|
181
|
+
const reserveIn = isToken0 ? BigInt(reserves[0]) : BigInt(reserves[1]);
|
|
182
|
+
const reserveOut = isToken0 ? BigInt(reserves[1]) : BigInt(reserves[0]);
|
|
183
|
+
if (reserveIn === 0n || reserveOut === 0n)
|
|
184
|
+
return null;
|
|
185
|
+
// Constant-product AMM with fee in ppm (parts per million: 1,000,000)
|
|
186
|
+
// e.g. 3000 fee = 0.3%
|
|
187
|
+
const amountInWithFee = amountIn * BigInt(1_000_000 - fee);
|
|
188
|
+
const numerator = amountInWithFee * reserveOut;
|
|
189
|
+
const denominator = reserveIn * 1000000n + amountInWithFee;
|
|
190
|
+
const amountOut = numerator / denominator;
|
|
191
|
+
return {
|
|
192
|
+
dexName,
|
|
193
|
+
poolType: 'v2',
|
|
194
|
+
poolAddress: pair,
|
|
195
|
+
amountOut,
|
|
196
|
+
fee,
|
|
197
|
+
reserveIn,
|
|
198
|
+
reserveOut,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
exports.LitVMQuoter = LitVMQuoter;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Address } from 'viem';
|
|
2
|
+
import type { BuildSwapTxParams, PreparedTransaction } from '../types/index.js';
|
|
3
|
+
export declare class LitVMSwapBuilder {
|
|
4
|
+
/**
|
|
5
|
+
* Prepares a ready-to-sign transaction for executing a swap
|
|
6
|
+
*/
|
|
7
|
+
static buildSwapTransaction(params: BuildSwapTxParams): PreparedTransaction;
|
|
8
|
+
/**
|
|
9
|
+
* Prepares an ERC-20 approval transaction
|
|
10
|
+
* @param tokenAddress The ERC-20 token contract
|
|
11
|
+
* @param spender The contract to approve (Defaults to AGGFlowEntrypoint)
|
|
12
|
+
* @param amount Optional amount to approve (defaults to max uint256)
|
|
13
|
+
*/
|
|
14
|
+
static buildApproveTransaction(tokenAddress: Address, spender?: Address, amount?: bigint): PreparedTransaction;
|
|
15
|
+
}
|