@mento-protocol/mento-sdk 3.0.0-rc.1 → 3.1.0-beta.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/dist/cache/routes.js +225 -1
- package/dist/cache/tokens.d.ts +1 -0
- package/dist/cache/tokens.js +31 -1
- package/dist/core/abis/reserve.d.ts +1 -0
- package/dist/core/abis/reserve.js +9 -1
- package/dist/core/constants/addresses.d.ts +5 -0
- package/dist/core/constants/addresses.js +29 -5
- package/dist/core/constants/chainId.d.ts +3 -1
- package/dist/core/constants/chainId.js +2 -0
- package/dist/esm/cache/routes.js +225 -1
- package/dist/esm/cache/tokens.js +31 -1
- package/dist/esm/core/abis/reserve.js +8 -0
- package/dist/esm/core/constants/addresses.js +28 -5
- package/dist/esm/core/constants/chainId.js +2 -0
- package/dist/esm/services/pools/poolDiscovery.js +4 -4
- package/dist/esm/services/swap/SwapService.js +13 -0
- package/dist/esm/services/tokens/tokenService.js +63 -11
- package/dist/esm/services/trading/TradingLimitsService.js +5 -2
- package/dist/esm/utils/chainConfig.js +49 -0
- package/dist/services/pools/poolDiscovery.js +3 -3
- package/dist/services/swap/SwapService.d.ts +7 -0
- package/dist/services/swap/SwapService.js +13 -0
- package/dist/services/tokens/tokenService.d.ts +17 -2
- package/dist/services/tokens/tokenService.js +61 -9
- package/dist/services/trading/TradingLimitsService.js +4 -1
- package/dist/utils/chainConfig.js +49 -0
- package/package.json +1 -1
package/dist/esm/cache/tokens.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// This file is auto-generated. Do not edit manually.
|
|
2
|
-
// Generated on 2026-03-
|
|
2
|
+
// Generated on 2026-03-10T12:14:17.694Z
|
|
3
3
|
/**
|
|
4
4
|
* Enum of all token symbols across all supported chains
|
|
5
5
|
*/
|
|
6
6
|
export var TokenSymbol;
|
|
7
7
|
(function (TokenSymbol) {
|
|
8
8
|
TokenSymbol["AUDm"] = "AUDm";
|
|
9
|
+
TokenSymbol["AUSD"] = "AUSD";
|
|
9
10
|
TokenSymbol["BRLm"] = "BRLm";
|
|
10
11
|
TokenSymbol["CADm"] = "CADm";
|
|
11
12
|
TokenSymbol["CELO"] = "CELO";
|
|
@@ -30,6 +31,29 @@ export var TokenSymbol;
|
|
|
30
31
|
* Cached tokens indexed by chain ID
|
|
31
32
|
*/
|
|
32
33
|
export const cachedTokens = {
|
|
34
|
+
// Chain 143
|
|
35
|
+
143: [],
|
|
36
|
+
// Chain 10143
|
|
37
|
+
10143: [
|
|
38
|
+
{
|
|
39
|
+
address: '0x5eCc03111ad2A78F981A108759bc73BAE2AB31bc',
|
|
40
|
+
symbol: TokenSymbol.USDm,
|
|
41
|
+
name: 'Mento Dollar',
|
|
42
|
+
decimals: 18,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
address: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
46
|
+
symbol: TokenSymbol.USDC,
|
|
47
|
+
name: 'USDC',
|
|
48
|
+
decimals: 6,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
address: '0x502E67D3fE9302A5e4Ec1CFCDdbD6F34F9B9484B',
|
|
52
|
+
symbol: TokenSymbol.AUSD,
|
|
53
|
+
name: 'Mento Mock AUSD',
|
|
54
|
+
decimals: 6,
|
|
55
|
+
}
|
|
56
|
+
],
|
|
33
57
|
// Chain 42220
|
|
34
58
|
42220: [
|
|
35
59
|
{
|
|
@@ -282,6 +306,12 @@ export const cachedTokens = {
|
|
|
282
306
|
* Useful for quickly looking up a token address by its symbol on a specific chain
|
|
283
307
|
*/
|
|
284
308
|
export const TOKEN_ADDRESSES_BY_CHAIN = {
|
|
309
|
+
143: {},
|
|
310
|
+
10143: {
|
|
311
|
+
[TokenSymbol.USDm]: '0x5eCc03111ad2A78F981A108759bc73BAE2AB31bc',
|
|
312
|
+
[TokenSymbol.USDC]: '0x534b2f3A21130d7a60830c2Df862319e593943A3',
|
|
313
|
+
[TokenSymbol.AUSD]: '0x502E67D3fE9302A5e4Ec1CFCDdbD6F34F9B9484B',
|
|
314
|
+
},
|
|
285
315
|
42220: {
|
|
286
316
|
[TokenSymbol.USDm]: '0x765DE816845861e75A25fCA122bb6898B8B1282a',
|
|
287
317
|
[TokenSymbol.EURm]: '0xD8763CBa276a3738E6DE85b4b3bF5FDed6D6cA73',
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { parseAbi } from 'viem';
|
|
2
|
+
// Legacy Reserve (Celo)
|
|
2
3
|
export const RESERVE_ABI = parseAbi([
|
|
3
4
|
'function getTokens() view returns (address[])',
|
|
4
5
|
'function isToken(address) view returns (bool)',
|
|
5
6
|
'function isCollateralAsset(address) view returns (bool)',
|
|
6
7
|
]);
|
|
8
|
+
// ReserveV2 (Monad)
|
|
9
|
+
export const RESERVE_V2_ABI = parseAbi([
|
|
10
|
+
'function getStableAssets() view returns (address[])',
|
|
11
|
+
'function getCollateralAssets() view returns (address[])',
|
|
12
|
+
'function isStableAsset(address) view returns (bool)',
|
|
13
|
+
'function isCollateralAsset(address) view returns (bool)',
|
|
14
|
+
]);
|
|
@@ -29,6 +29,22 @@ export const addresses = {
|
|
|
29
29
|
ReserveLiquidityStrategy: '0xa0fB8b16ce6AF3634fF9F3f4F40E49E1C1ae4f0B',
|
|
30
30
|
CDPLiquidityStrategy: '0x4e78BD9565341EAbe99cDC024acB044d9BDcB985',
|
|
31
31
|
},
|
|
32
|
+
[ChainId.MONAD_TESTNET]: {
|
|
33
|
+
// Oracles & Breakers
|
|
34
|
+
BreakerBox: '0x88869E30609D2C0E4032463D713328C6f541878e',
|
|
35
|
+
MedianDeltaBreaker: '0xf923C884F319b8866F67C5719A80E5cB4D0FAF2c',
|
|
36
|
+
SortedOracles: '0x85ed9ac57827132B8F60938F3165BC139E1F53cd',
|
|
37
|
+
ValueDeltaBreaker: '0xbbD0D093F5F11D16D4456FBd6229c9a3b70B8Aaf',
|
|
38
|
+
// DEX
|
|
39
|
+
Reserve: '0xbCdc1D0b92DfceEaa0FcD0a0D53355F4bF1DB8a7',
|
|
40
|
+
// Stable Tokens
|
|
41
|
+
StableToken: '0x5eCc03111ad2A78F981A108759bc73BAE2AB31bc', // USDm
|
|
42
|
+
// V3
|
|
43
|
+
FPMMFactory: '0x353ED52bF8482027C0e0b9e3c0e5d96A9F680980',
|
|
44
|
+
Router: '0xcf6cD45210b3ffE3cA28379C4683F1e60D0C2CCd',
|
|
45
|
+
ReserveLiquidityStrategy: '0x734bb3251Ec3f1A83f8f2A8609bcEF649D54EbF8',
|
|
46
|
+
},
|
|
47
|
+
[ChainId.MONAD]: {},
|
|
32
48
|
[ChainId.CELO_SEPOLIA]: {
|
|
33
49
|
// Oracles & Breakers
|
|
34
50
|
BreakerBox: '0x578bD46003B9D3fd4c3C3f47c98B329562a6a1dE',
|
|
@@ -56,6 +72,17 @@ export const addresses = {
|
|
|
56
72
|
CDPLiquidityStrategy: '0x065AE7D4e207C8f4dca112D0B79E668cc7e93e03',
|
|
57
73
|
},
|
|
58
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Get the address of a contract for a given chain, returning undefined if not found.
|
|
77
|
+
* Use this when the contract may not be deployed on the target chain.
|
|
78
|
+
*/
|
|
79
|
+
export function tryGetContractAddress(chainId, contractName) {
|
|
80
|
+
const addressesForChain = addresses[chainId];
|
|
81
|
+
if (!addressesForChain) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
return addressesForChain[contractName];
|
|
85
|
+
}
|
|
59
86
|
/**
|
|
60
87
|
* Get the address of a contract for a given chain
|
|
61
88
|
* @param chainId - The chain ID
|
|
@@ -64,11 +91,7 @@ export const addresses = {
|
|
|
64
91
|
* @throws Error if the address is not found for the given chain
|
|
65
92
|
*/
|
|
66
93
|
export function getContractAddress(chainId, contractName) {
|
|
67
|
-
const
|
|
68
|
-
if (!addressesForChain) {
|
|
69
|
-
throw new Error(`No addresses found for chain ID ${chainId}`);
|
|
70
|
-
}
|
|
71
|
-
const address = addressesForChain[contractName];
|
|
94
|
+
const address = tryGetContractAddress(chainId, contractName);
|
|
72
95
|
if (!address) {
|
|
73
96
|
throw new Error(`Address not found for contract ${contractName} on chain ID ${chainId}`);
|
|
74
97
|
}
|
|
@@ -2,4 +2,6 @@ export var ChainId;
|
|
|
2
2
|
(function (ChainId) {
|
|
3
3
|
ChainId[ChainId["CELO"] = 42220] = "CELO";
|
|
4
4
|
ChainId[ChainId["CELO_SEPOLIA"] = 11142220] = "CELO_SEPOLIA";
|
|
5
|
+
ChainId[ChainId["MONAD_TESTNET"] = 10143] = "MONAD_TESTNET";
|
|
6
|
+
ChainId[ChainId["MONAD"] = 143] = "MONAD";
|
|
5
7
|
})(ChainId || (ChainId = {}));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryGetContractAddress } from '../../core/constants';
|
|
2
2
|
import { PoolType } from '../../core/types';
|
|
3
3
|
import { FPMM_FACTORY_ABI, FPMM_ABI, VIRTUAL_POOL_FACTORY_ABI, VIRTUAL_POOL_ABI, BIPOOL_MANAGER_ABI, } from '../../core/abis';
|
|
4
4
|
import { sortTokenAddresses } from '../../utils/sortUtils';
|
|
@@ -6,7 +6,7 @@ import { sortTokenAddresses } from '../../utils/sortUtils';
|
|
|
6
6
|
* Fetches all FPMM pools from the FPMM Factory
|
|
7
7
|
*/
|
|
8
8
|
export async function fetchFPMMPools(publicClient, chainId) {
|
|
9
|
-
const fpmmFactoryAddress =
|
|
9
|
+
const fpmmFactoryAddress = tryGetContractAddress(chainId, 'FPMMFactory');
|
|
10
10
|
if (!fpmmFactoryAddress) {
|
|
11
11
|
return [];
|
|
12
12
|
}
|
|
@@ -52,8 +52,8 @@ export async function fetchFPMMPools(publicClient, chainId) {
|
|
|
52
52
|
* then resolves token pairs and exchange IDs from each pool and BiPoolManager.
|
|
53
53
|
*/
|
|
54
54
|
export async function fetchVirtualPools(publicClient, chainId) {
|
|
55
|
-
const virtualPoolFactoryAddress =
|
|
56
|
-
const biPoolManagerAddress =
|
|
55
|
+
const virtualPoolFactoryAddress = tryGetContractAddress(chainId, 'VirtualPoolFactory');
|
|
56
|
+
const biPoolManagerAddress = tryGetContractAddress(chainId, 'BiPoolManager');
|
|
57
57
|
if (!virtualPoolFactoryAddress || !biPoolManagerAddress) {
|
|
58
58
|
return [];
|
|
59
59
|
}
|
|
@@ -27,6 +27,7 @@ export class SwapService {
|
|
|
27
27
|
* @param options - Swap configuration options (slippage, deadline)
|
|
28
28
|
* @param route - Optional pre-fetched route for better performance
|
|
29
29
|
* @returns Combined transaction with approval (if needed) and swap params
|
|
30
|
+
* @throws {Error} 'amountIn must be greater than zero' - if amountIn <= 0
|
|
30
31
|
* @throws {Error} 'Slippage tolerance cannot be negative' - if slippageTolerance < 0
|
|
31
32
|
* @throws {Error} 'Slippage tolerance exceeds maximum' - if slippageTolerance > 20%
|
|
32
33
|
* @throws {Error} 'Deadline must be in the future' - if deadline is not a future timestamp
|
|
@@ -54,6 +55,7 @@ export class SwapService {
|
|
|
54
55
|
* ```
|
|
55
56
|
*/
|
|
56
57
|
async buildSwapTransaction(tokenIn, tokenOut, amountIn, recipient, owner, options, route) {
|
|
58
|
+
this.validateAmountIn(amountIn);
|
|
57
59
|
// Validate all address inputs
|
|
58
60
|
validateAddress(tokenIn, 'tokenIn');
|
|
59
61
|
validateAddress(tokenOut, 'tokenOut');
|
|
@@ -77,6 +79,7 @@ export class SwapService {
|
|
|
77
79
|
* @param options - Swap configuration options (slippage, deadline)
|
|
78
80
|
* @param route - Optional pre-fetched route for better performance
|
|
79
81
|
* @returns Detailed swap parameters including transaction data
|
|
82
|
+
* @throws {Error} 'amountIn must be greater than zero' - if amountIn <= 0
|
|
80
83
|
* @throws {Error} 'Slippage tolerance cannot be negative' - if slippageTolerance < 0
|
|
81
84
|
* @throws {Error} 'Slippage tolerance exceeds maximum' - if slippageTolerance > 20%
|
|
82
85
|
* @throws {Error} 'Deadline must be in the future' - if deadline is not a future timestamp
|
|
@@ -98,6 +101,7 @@ export class SwapService {
|
|
|
98
101
|
* ```
|
|
99
102
|
*/
|
|
100
103
|
async buildSwapParams(tokenIn, tokenOut, amountIn, recipient, options, route) {
|
|
104
|
+
this.validateAmountIn(amountIn);
|
|
101
105
|
const deadline = options.deadline;
|
|
102
106
|
if (deadline <= BigInt(Date.now()) / 1000n) {
|
|
103
107
|
throw new Error('Deadline must be in the future');
|
|
@@ -155,6 +159,15 @@ export class SwapService {
|
|
|
155
159
|
args: [owner, routerAddress],
|
|
156
160
|
}));
|
|
157
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Validates that the input amount is strictly positive.
|
|
164
|
+
* @private
|
|
165
|
+
*/
|
|
166
|
+
validateAmountIn(amountIn) {
|
|
167
|
+
if (amountIn <= 0n) {
|
|
168
|
+
throw new Error('amountIn must be greater than zero');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
158
171
|
/**
|
|
159
172
|
* Calculates minimum output amount after applying slippage tolerance
|
|
160
173
|
* @param amountOut - Expected output amount
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import { RESERVE_ABI, BIPOOL_MANAGER_ABI, ERC20_ABI } from '../../core/abis';
|
|
2
|
-
import { getContractAddress, RESERVE, BIPOOLMANAGER, } from '../../core/constants';
|
|
1
|
+
import { RESERVE_ABI, RESERVE_V2_ABI, BIPOOL_MANAGER_ABI, ERC20_ABI } from '../../core/abis';
|
|
2
|
+
import { getContractAddress, tryGetContractAddress, ChainId, RESERVE, BIPOOLMANAGER, } from '../../core/constants';
|
|
3
3
|
import { retryOperation } from '../../utils';
|
|
4
|
+
/**
|
|
5
|
+
* Chains that use ReserveV2 (v3) instead of the legacy Reserve contract.
|
|
6
|
+
*/
|
|
7
|
+
const RESERVE_V2_CHAINS = new Set([ChainId.MONAD_TESTNET, ChainId.MONAD]);
|
|
4
8
|
export class TokenService {
|
|
5
9
|
constructor(publicClient, chainId) {
|
|
6
10
|
this.publicClient = publicClient;
|
|
7
11
|
this.chainId = chainId;
|
|
8
12
|
}
|
|
13
|
+
isReserveV2() {
|
|
14
|
+
return RESERVE_V2_CHAINS.has(this.chainId);
|
|
15
|
+
}
|
|
9
16
|
/**
|
|
10
17
|
* Get token metadata (name, symbol, decimals)
|
|
11
18
|
* @param address - Token contract address
|
|
@@ -52,6 +59,26 @@ export class TokenService {
|
|
|
52
59
|
}));
|
|
53
60
|
return totalSupply.toString();
|
|
54
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Get stable token addresses from the Reserve contract.
|
|
64
|
+
* Uses getStableAssets() on ReserveV2, getTokens() on legacy Reserve.
|
|
65
|
+
*/
|
|
66
|
+
async getStableTokenAddresses(reserveAddress) {
|
|
67
|
+
if (this.isReserveV2()) {
|
|
68
|
+
return (await this.publicClient.readContract({
|
|
69
|
+
address: reserveAddress,
|
|
70
|
+
abi: RESERVE_V2_ABI,
|
|
71
|
+
functionName: 'getStableAssets',
|
|
72
|
+
args: [],
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
return (await this.publicClient.readContract({
|
|
76
|
+
address: reserveAddress,
|
|
77
|
+
abi: RESERVE_ABI,
|
|
78
|
+
functionName: 'getTokens',
|
|
79
|
+
args: [],
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
55
82
|
/**
|
|
56
83
|
* Get all stable tokens from the Reserve contract.
|
|
57
84
|
* Returns the actual on-chain ERC20 totalSupply values without adjustments.
|
|
@@ -60,12 +87,7 @@ export class TokenService {
|
|
|
60
87
|
*/
|
|
61
88
|
async getStableTokens(includeSupply = true) {
|
|
62
89
|
const reserveAddress = getContractAddress(this.chainId, RESERVE);
|
|
63
|
-
const tokenAddresses =
|
|
64
|
-
address: reserveAddress,
|
|
65
|
-
abi: RESERVE_ABI,
|
|
66
|
-
functionName: 'getTokens',
|
|
67
|
-
args: [],
|
|
68
|
-
}));
|
|
90
|
+
const tokenAddresses = await this.getStableTokenAddresses(reserveAddress);
|
|
69
91
|
// Fetch metadata and totalSupply for all tokens concurrently
|
|
70
92
|
const tokens = await Promise.all(tokenAddresses.map(async (address) => {
|
|
71
93
|
const [metadata, totalSupply] = await Promise.all([
|
|
@@ -81,12 +103,42 @@ export class TokenService {
|
|
|
81
103
|
return tokens;
|
|
82
104
|
}
|
|
83
105
|
/**
|
|
84
|
-
* Get all collateral assets
|
|
85
|
-
*
|
|
106
|
+
* Get all collateral assets.
|
|
107
|
+
* On ReserveV2 chains, queries the reserve directly.
|
|
108
|
+
* On legacy chains, discovers collateral via BiPoolManager exchanges.
|
|
86
109
|
* @returns Array of collateral assets
|
|
87
110
|
*/
|
|
88
111
|
async getCollateralAssets() {
|
|
89
|
-
|
|
112
|
+
if (this.isReserveV2()) {
|
|
113
|
+
return this.getCollateralAssetsV2();
|
|
114
|
+
}
|
|
115
|
+
return this.getCollateralAssetsLegacy();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get collateral assets directly from ReserveV2.
|
|
119
|
+
*/
|
|
120
|
+
async getCollateralAssetsV2() {
|
|
121
|
+
const reserveAddress = getContractAddress(this.chainId, RESERVE);
|
|
122
|
+
const collateralAddresses = (await retryOperation(() => this.publicClient.readContract({
|
|
123
|
+
address: reserveAddress,
|
|
124
|
+
abi: RESERVE_V2_ABI,
|
|
125
|
+
functionName: 'getCollateralAssets',
|
|
126
|
+
args: [],
|
|
127
|
+
})));
|
|
128
|
+
const assets = await Promise.all(collateralAddresses.map(async (address) => {
|
|
129
|
+
const metadata = await this.getTokenMetadata(address);
|
|
130
|
+
return { address, ...metadata };
|
|
131
|
+
}));
|
|
132
|
+
return assets;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Get collateral assets from legacy Reserve via BiPoolManager exchanges.
|
|
136
|
+
*/
|
|
137
|
+
async getCollateralAssetsLegacy() {
|
|
138
|
+
const biPoolManagerAddress = tryGetContractAddress(this.chainId, BIPOOLMANAGER);
|
|
139
|
+
if (!biPoolManagerAddress) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
90
142
|
const reserveAddress = getContractAddress(this.chainId, RESERVE);
|
|
91
143
|
// Get all exchanges to find unique token addresses
|
|
92
144
|
const exchanges = (await retryOperation(() => this.publicClient.readContract({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PoolType } from '../../core/types';
|
|
2
2
|
import { FPMM_ABI, BROKER_ABI } from '../../core/abis';
|
|
3
|
-
import {
|
|
3
|
+
import { tryGetContractAddress } from '../../core/constants';
|
|
4
4
|
import { computeLimitId, calculateTradingLimitsV1, calculateTradingLimitsV2, hasConfiguredLimitsV1, hasConfiguredLimitsV2, } from '../../utils/tradingLimits';
|
|
5
5
|
/**
|
|
6
6
|
* Service for querying trading limits from the Mento protocol.
|
|
@@ -97,7 +97,10 @@ export class TradingLimitsService {
|
|
|
97
97
|
* Get trading limits for a specific token in a Virtual pool.
|
|
98
98
|
*/
|
|
99
99
|
async getVirtualPoolTokenLimits(exchangeId, token) {
|
|
100
|
-
const brokerAddr =
|
|
100
|
+
const brokerAddr = tryGetContractAddress(this.chainId, 'Broker');
|
|
101
|
+
if (!brokerAddr) {
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
101
104
|
const limitId = computeLimitId(exchangeId, token);
|
|
102
105
|
try {
|
|
103
106
|
// Fetch config and state in parallel
|
|
@@ -23,6 +23,47 @@ const celoSepolia = defineChain({
|
|
|
23
23
|
},
|
|
24
24
|
testnet: true,
|
|
25
25
|
});
|
|
26
|
+
const monadTestnet = defineChain({
|
|
27
|
+
id: 10143,
|
|
28
|
+
name: 'Monad Testnet',
|
|
29
|
+
nativeCurrency: {
|
|
30
|
+
decimals: 18,
|
|
31
|
+
name: 'MON',
|
|
32
|
+
symbol: 'MON',
|
|
33
|
+
},
|
|
34
|
+
rpcUrls: {
|
|
35
|
+
default: {
|
|
36
|
+
http: ['https://testnet-rpc.monad.xyz'],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
blockExplorers: {
|
|
40
|
+
default: {
|
|
41
|
+
name: 'Monad Explorer',
|
|
42
|
+
url: 'https://testnet.monadexplorer.com',
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
testnet: true,
|
|
46
|
+
});
|
|
47
|
+
const monad = defineChain({
|
|
48
|
+
id: 143,
|
|
49
|
+
name: 'Monad',
|
|
50
|
+
nativeCurrency: {
|
|
51
|
+
decimals: 18,
|
|
52
|
+
name: 'MON',
|
|
53
|
+
symbol: 'MON',
|
|
54
|
+
},
|
|
55
|
+
rpcUrls: {
|
|
56
|
+
default: {
|
|
57
|
+
http: ['https://rpc.monad.xyz'],
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
blockExplorers: {
|
|
61
|
+
default: {
|
|
62
|
+
name: 'Monad Explorer',
|
|
63
|
+
url: 'https://monadvision.com',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
});
|
|
26
67
|
/**
|
|
27
68
|
* Get the default RPC URL for a given chain ID
|
|
28
69
|
* @param chainId - The chain ID
|
|
@@ -35,6 +76,10 @@ export function getDefaultRpcUrl(chainId) {
|
|
|
35
76
|
return 'https://forno.celo.org';
|
|
36
77
|
case ChainId.CELO_SEPOLIA:
|
|
37
78
|
return 'https://forno.celo-sepolia.celo-testnet.org';
|
|
79
|
+
case ChainId.MONAD_TESTNET:
|
|
80
|
+
return 'https://testnet-rpc.monad.xyz';
|
|
81
|
+
case ChainId.MONAD:
|
|
82
|
+
return 'https://rpc.monad.xyz';
|
|
38
83
|
default:
|
|
39
84
|
throw new Error(`Unsupported chain ID: ${chainId}`);
|
|
40
85
|
}
|
|
@@ -51,6 +96,10 @@ export function getChainConfig(chainId) {
|
|
|
51
96
|
return celo;
|
|
52
97
|
case ChainId.CELO_SEPOLIA:
|
|
53
98
|
return celoSepolia;
|
|
99
|
+
case ChainId.MONAD_TESTNET:
|
|
100
|
+
return monadTestnet;
|
|
101
|
+
case ChainId.MONAD:
|
|
102
|
+
return monad;
|
|
54
103
|
default:
|
|
55
104
|
throw new Error(`Unsupported chain ID: ${chainId}`);
|
|
56
105
|
}
|
|
@@ -10,7 +10,7 @@ const sortUtils_1 = require("../../utils/sortUtils");
|
|
|
10
10
|
* Fetches all FPMM pools from the FPMM Factory
|
|
11
11
|
*/
|
|
12
12
|
async function fetchFPMMPools(publicClient, chainId) {
|
|
13
|
-
const fpmmFactoryAddress = (0, constants_1.
|
|
13
|
+
const fpmmFactoryAddress = (0, constants_1.tryGetContractAddress)(chainId, 'FPMMFactory');
|
|
14
14
|
if (!fpmmFactoryAddress) {
|
|
15
15
|
return [];
|
|
16
16
|
}
|
|
@@ -56,8 +56,8 @@ async function fetchFPMMPools(publicClient, chainId) {
|
|
|
56
56
|
* then resolves token pairs and exchange IDs from each pool and BiPoolManager.
|
|
57
57
|
*/
|
|
58
58
|
async function fetchVirtualPools(publicClient, chainId) {
|
|
59
|
-
const virtualPoolFactoryAddress = (0, constants_1.
|
|
60
|
-
const biPoolManagerAddress = (0, constants_1.
|
|
59
|
+
const virtualPoolFactoryAddress = (0, constants_1.tryGetContractAddress)(chainId, 'VirtualPoolFactory');
|
|
60
|
+
const biPoolManagerAddress = (0, constants_1.tryGetContractAddress)(chainId, 'BiPoolManager');
|
|
61
61
|
if (!virtualPoolFactoryAddress || !biPoolManagerAddress) {
|
|
62
62
|
return [];
|
|
63
63
|
}
|
|
@@ -85,6 +85,7 @@ export declare class SwapService {
|
|
|
85
85
|
* @param options - Swap configuration options (slippage, deadline)
|
|
86
86
|
* @param route - Optional pre-fetched route for better performance
|
|
87
87
|
* @returns Combined transaction with approval (if needed) and swap params
|
|
88
|
+
* @throws {Error} 'amountIn must be greater than zero' - if amountIn <= 0
|
|
88
89
|
* @throws {Error} 'Slippage tolerance cannot be negative' - if slippageTolerance < 0
|
|
89
90
|
* @throws {Error} 'Slippage tolerance exceeds maximum' - if slippageTolerance > 20%
|
|
90
91
|
* @throws {Error} 'Deadline must be in the future' - if deadline is not a future timestamp
|
|
@@ -123,6 +124,7 @@ export declare class SwapService {
|
|
|
123
124
|
* @param options - Swap configuration options (slippage, deadline)
|
|
124
125
|
* @param route - Optional pre-fetched route for better performance
|
|
125
126
|
* @returns Detailed swap parameters including transaction data
|
|
127
|
+
* @throws {Error} 'amountIn must be greater than zero' - if amountIn <= 0
|
|
126
128
|
* @throws {Error} 'Slippage tolerance cannot be negative' - if slippageTolerance < 0
|
|
127
129
|
* @throws {Error} 'Slippage tolerance exceeds maximum' - if slippageTolerance > 20%
|
|
128
130
|
* @throws {Error} 'Deadline must be in the future' - if deadline is not a future timestamp
|
|
@@ -154,6 +156,11 @@ export declare class SwapService {
|
|
|
154
156
|
* @private
|
|
155
157
|
*/
|
|
156
158
|
private getAllowance;
|
|
159
|
+
/**
|
|
160
|
+
* Validates that the input amount is strictly positive.
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
private validateAmountIn;
|
|
157
164
|
/**
|
|
158
165
|
* Calculates minimum output amount after applying slippage tolerance
|
|
159
166
|
* @param amountOut - Expected output amount
|
|
@@ -30,6 +30,7 @@ class SwapService {
|
|
|
30
30
|
* @param options - Swap configuration options (slippage, deadline)
|
|
31
31
|
* @param route - Optional pre-fetched route for better performance
|
|
32
32
|
* @returns Combined transaction with approval (if needed) and swap params
|
|
33
|
+
* @throws {Error} 'amountIn must be greater than zero' - if amountIn <= 0
|
|
33
34
|
* @throws {Error} 'Slippage tolerance cannot be negative' - if slippageTolerance < 0
|
|
34
35
|
* @throws {Error} 'Slippage tolerance exceeds maximum' - if slippageTolerance > 20%
|
|
35
36
|
* @throws {Error} 'Deadline must be in the future' - if deadline is not a future timestamp
|
|
@@ -57,6 +58,7 @@ class SwapService {
|
|
|
57
58
|
* ```
|
|
58
59
|
*/
|
|
59
60
|
async buildSwapTransaction(tokenIn, tokenOut, amountIn, recipient, owner, options, route) {
|
|
61
|
+
this.validateAmountIn(amountIn);
|
|
60
62
|
// Validate all address inputs
|
|
61
63
|
(0, validation_1.validateAddress)(tokenIn, 'tokenIn');
|
|
62
64
|
(0, validation_1.validateAddress)(tokenOut, 'tokenOut');
|
|
@@ -80,6 +82,7 @@ class SwapService {
|
|
|
80
82
|
* @param options - Swap configuration options (slippage, deadline)
|
|
81
83
|
* @param route - Optional pre-fetched route for better performance
|
|
82
84
|
* @returns Detailed swap parameters including transaction data
|
|
85
|
+
* @throws {Error} 'amountIn must be greater than zero' - if amountIn <= 0
|
|
83
86
|
* @throws {Error} 'Slippage tolerance cannot be negative' - if slippageTolerance < 0
|
|
84
87
|
* @throws {Error} 'Slippage tolerance exceeds maximum' - if slippageTolerance > 20%
|
|
85
88
|
* @throws {Error} 'Deadline must be in the future' - if deadline is not a future timestamp
|
|
@@ -101,6 +104,7 @@ class SwapService {
|
|
|
101
104
|
* ```
|
|
102
105
|
*/
|
|
103
106
|
async buildSwapParams(tokenIn, tokenOut, amountIn, recipient, options, route) {
|
|
107
|
+
this.validateAmountIn(amountIn);
|
|
104
108
|
const deadline = options.deadline;
|
|
105
109
|
if (deadline <= BigInt(Date.now()) / 1000n) {
|
|
106
110
|
throw new Error('Deadline must be in the future');
|
|
@@ -158,6 +162,15 @@ class SwapService {
|
|
|
158
162
|
args: [owner, routerAddress],
|
|
159
163
|
}));
|
|
160
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Validates that the input amount is strictly positive.
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
validateAmountIn(amountIn) {
|
|
170
|
+
if (amountIn <= 0n) {
|
|
171
|
+
throw new Error('amountIn must be greater than zero');
|
|
172
|
+
}
|
|
173
|
+
}
|
|
161
174
|
/**
|
|
162
175
|
* Calculates minimum output amount after applying slippage tolerance
|
|
163
176
|
* @param amountOut - Expected output amount
|
|
@@ -4,6 +4,7 @@ export declare class TokenService {
|
|
|
4
4
|
private publicClient;
|
|
5
5
|
private chainId;
|
|
6
6
|
constructor(publicClient: PublicClient, chainId: number);
|
|
7
|
+
private isReserveV2;
|
|
7
8
|
/**
|
|
8
9
|
* Get token metadata (name, symbol, decimals)
|
|
9
10
|
* @param address - Token contract address
|
|
@@ -16,6 +17,11 @@ export declare class TokenService {
|
|
|
16
17
|
* @returns Total supply as string
|
|
17
18
|
*/
|
|
18
19
|
private getTotalSupply;
|
|
20
|
+
/**
|
|
21
|
+
* Get stable token addresses from the Reserve contract.
|
|
22
|
+
* Uses getStableAssets() on ReserveV2, getTokens() on legacy Reserve.
|
|
23
|
+
*/
|
|
24
|
+
private getStableTokenAddresses;
|
|
19
25
|
/**
|
|
20
26
|
* Get all stable tokens from the Reserve contract.
|
|
21
27
|
* Returns the actual on-chain ERC20 totalSupply values without adjustments.
|
|
@@ -24,10 +30,19 @@ export declare class TokenService {
|
|
|
24
30
|
*/
|
|
25
31
|
getStableTokens(includeSupply?: boolean): Promise<StableToken[]>;
|
|
26
32
|
/**
|
|
27
|
-
* Get all collateral assets
|
|
28
|
-
*
|
|
33
|
+
* Get all collateral assets.
|
|
34
|
+
* On ReserveV2 chains, queries the reserve directly.
|
|
35
|
+
* On legacy chains, discovers collateral via BiPoolManager exchanges.
|
|
29
36
|
* @returns Array of collateral assets
|
|
30
37
|
*/
|
|
31
38
|
getCollateralAssets(): Promise<CollateralAsset[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Get collateral assets directly from ReserveV2.
|
|
41
|
+
*/
|
|
42
|
+
private getCollateralAssetsV2;
|
|
43
|
+
/**
|
|
44
|
+
* Get collateral assets from legacy Reserve via BiPoolManager exchanges.
|
|
45
|
+
*/
|
|
46
|
+
private getCollateralAssetsLegacy;
|
|
32
47
|
}
|
|
33
48
|
//# sourceMappingURL=tokenService.d.ts.map
|
|
@@ -4,11 +4,18 @@ exports.TokenService = void 0;
|
|
|
4
4
|
const abis_1 = require("../../core/abis");
|
|
5
5
|
const constants_1 = require("../../core/constants");
|
|
6
6
|
const utils_1 = require("../../utils");
|
|
7
|
+
/**
|
|
8
|
+
* Chains that use ReserveV2 (v3) instead of the legacy Reserve contract.
|
|
9
|
+
*/
|
|
10
|
+
const RESERVE_V2_CHAINS = new Set([constants_1.ChainId.MONAD_TESTNET, constants_1.ChainId.MONAD]);
|
|
7
11
|
class TokenService {
|
|
8
12
|
constructor(publicClient, chainId) {
|
|
9
13
|
this.publicClient = publicClient;
|
|
10
14
|
this.chainId = chainId;
|
|
11
15
|
}
|
|
16
|
+
isReserveV2() {
|
|
17
|
+
return RESERVE_V2_CHAINS.has(this.chainId);
|
|
18
|
+
}
|
|
12
19
|
/**
|
|
13
20
|
* Get token metadata (name, symbol, decimals)
|
|
14
21
|
* @param address - Token contract address
|
|
@@ -55,6 +62,26 @@ class TokenService {
|
|
|
55
62
|
}));
|
|
56
63
|
return totalSupply.toString();
|
|
57
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Get stable token addresses from the Reserve contract.
|
|
67
|
+
* Uses getStableAssets() on ReserveV2, getTokens() on legacy Reserve.
|
|
68
|
+
*/
|
|
69
|
+
async getStableTokenAddresses(reserveAddress) {
|
|
70
|
+
if (this.isReserveV2()) {
|
|
71
|
+
return (await this.publicClient.readContract({
|
|
72
|
+
address: reserveAddress,
|
|
73
|
+
abi: abis_1.RESERVE_V2_ABI,
|
|
74
|
+
functionName: 'getStableAssets',
|
|
75
|
+
args: [],
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
return (await this.publicClient.readContract({
|
|
79
|
+
address: reserveAddress,
|
|
80
|
+
abi: abis_1.RESERVE_ABI,
|
|
81
|
+
functionName: 'getTokens',
|
|
82
|
+
args: [],
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
58
85
|
/**
|
|
59
86
|
* Get all stable tokens from the Reserve contract.
|
|
60
87
|
* Returns the actual on-chain ERC20 totalSupply values without adjustments.
|
|
@@ -63,12 +90,7 @@ class TokenService {
|
|
|
63
90
|
*/
|
|
64
91
|
async getStableTokens(includeSupply = true) {
|
|
65
92
|
const reserveAddress = (0, constants_1.getContractAddress)(this.chainId, constants_1.RESERVE);
|
|
66
|
-
const tokenAddresses =
|
|
67
|
-
address: reserveAddress,
|
|
68
|
-
abi: abis_1.RESERVE_ABI,
|
|
69
|
-
functionName: 'getTokens',
|
|
70
|
-
args: [],
|
|
71
|
-
}));
|
|
93
|
+
const tokenAddresses = await this.getStableTokenAddresses(reserveAddress);
|
|
72
94
|
// Fetch metadata and totalSupply for all tokens concurrently
|
|
73
95
|
const tokens = await Promise.all(tokenAddresses.map(async (address) => {
|
|
74
96
|
const [metadata, totalSupply] = await Promise.all([
|
|
@@ -84,12 +106,42 @@ class TokenService {
|
|
|
84
106
|
return tokens;
|
|
85
107
|
}
|
|
86
108
|
/**
|
|
87
|
-
* Get all collateral assets
|
|
88
|
-
*
|
|
109
|
+
* Get all collateral assets.
|
|
110
|
+
* On ReserveV2 chains, queries the reserve directly.
|
|
111
|
+
* On legacy chains, discovers collateral via BiPoolManager exchanges.
|
|
89
112
|
* @returns Array of collateral assets
|
|
90
113
|
*/
|
|
91
114
|
async getCollateralAssets() {
|
|
92
|
-
|
|
115
|
+
if (this.isReserveV2()) {
|
|
116
|
+
return this.getCollateralAssetsV2();
|
|
117
|
+
}
|
|
118
|
+
return this.getCollateralAssetsLegacy();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get collateral assets directly from ReserveV2.
|
|
122
|
+
*/
|
|
123
|
+
async getCollateralAssetsV2() {
|
|
124
|
+
const reserveAddress = (0, constants_1.getContractAddress)(this.chainId, constants_1.RESERVE);
|
|
125
|
+
const collateralAddresses = (await (0, utils_1.retryOperation)(() => this.publicClient.readContract({
|
|
126
|
+
address: reserveAddress,
|
|
127
|
+
abi: abis_1.RESERVE_V2_ABI,
|
|
128
|
+
functionName: 'getCollateralAssets',
|
|
129
|
+
args: [],
|
|
130
|
+
})));
|
|
131
|
+
const assets = await Promise.all(collateralAddresses.map(async (address) => {
|
|
132
|
+
const metadata = await this.getTokenMetadata(address);
|
|
133
|
+
return { address, ...metadata };
|
|
134
|
+
}));
|
|
135
|
+
return assets;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get collateral assets from legacy Reserve via BiPoolManager exchanges.
|
|
139
|
+
*/
|
|
140
|
+
async getCollateralAssetsLegacy() {
|
|
141
|
+
const biPoolManagerAddress = (0, constants_1.tryGetContractAddress)(this.chainId, constants_1.BIPOOLMANAGER);
|
|
142
|
+
if (!biPoolManagerAddress) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
93
145
|
const reserveAddress = (0, constants_1.getContractAddress)(this.chainId, constants_1.RESERVE);
|
|
94
146
|
// Get all exchanges to find unique token addresses
|
|
95
147
|
const exchanges = (await (0, utils_1.retryOperation)(() => this.publicClient.readContract({
|
|
@@ -100,7 +100,10 @@ class TradingLimitsService {
|
|
|
100
100
|
* Get trading limits for a specific token in a Virtual pool.
|
|
101
101
|
*/
|
|
102
102
|
async getVirtualPoolTokenLimits(exchangeId, token) {
|
|
103
|
-
const brokerAddr = (0, constants_1.
|
|
103
|
+
const brokerAddr = (0, constants_1.tryGetContractAddress)(this.chainId, 'Broker');
|
|
104
|
+
if (!brokerAddr) {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
104
107
|
const limitId = (0, tradingLimits_1.computeLimitId)(exchangeId, token);
|
|
105
108
|
try {
|
|
106
109
|
// Fetch config and state in parallel
|