@curvefi/api 2.69.17 → 2.70.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/README.md CHANGED
@@ -325,6 +325,98 @@ import curve from "@curvefi/api";
325
325
  })()
326
326
  ````
327
327
 
328
+ ### Building a pool from external data (getPoolByData)
329
+
330
+ `curve.getPoolByData(data)` builds a fully working pool from an externally supplied descriptor,
331
+ without calling `fetchPools` first. Use it when the pool metadata comes from your own source
332
+ (backend, cache, DB) instead of Curve's API. curve resolves all the ABIs (swap / gauge / zap / LP)
333
+ itself from `poolType` + `implementationAddress` + `isMetaPool` — you don't pass any ABI.
334
+
335
+ The descriptor (`IExternalPoolData`) mirrors the shape of the `getPools/{network}/{poolType}` API:
336
+
337
+ ```ts
338
+ interface IExternalPoolData {
339
+ poolType: 'factory' | 'factory-crvusd' | 'factory-crypto' | 'factory-twocrypto' | 'factory-tricrypto' | 'factory-stable-ng',
340
+ address: string, // swap address
341
+ coins: { address: string, symbol: string, decimals: number | string }[],
342
+ id?: string, // registry handle; defaults to address
343
+ name?: string,
344
+ symbol?: string,
345
+ lpTokenAddress?: string, // separate LP token for old crypto pools; defaults to address
346
+ gaugeAddress?: string,
347
+ implementationAddress?: string, // REQUIRED for 'factory' (old stable) and 'factory-tricrypto'
348
+ isMetaPool?: boolean,
349
+ basePoolAddress?: string, // REQUIRED when isMetaPool
350
+ assetTypeName?: string,
351
+ }
352
+ ```
353
+
354
+ ```ts
355
+ import curve from "@curvefi/api";
356
+
357
+ (async () => {
358
+ await curve.init('JsonRpc', {}, { gasPrice: 0, maxFeePerGas: 0, maxPriorityFeePerGas: 0 });
359
+
360
+ const pool = curve.getPoolByData({
361
+ poolType: 'factory-stable-ng',
362
+ address: '0x...',
363
+ isMetaPool: false,
364
+ coins: [
365
+ { address: '0x...', symbol: 'USDC', decimals: 6 },
366
+ { address: '0x...', symbol: 'USDT', decimals: 6 },
367
+ ],
368
+ });
369
+
370
+ // From here the pool behaves exactly like one returned by curve.getPool(...)
371
+ pool.underlyingCoins; // ['USDC', 'USDT']
372
+ await pool.deposit(['1', '1']);
373
+ })()
374
+ ```
375
+
376
+ ### Meta pools: base pool dependencies
377
+
378
+ A meta pool is built on top of a base pool, and its descriptor does **not** carry the base pool's
379
+ coins/decimals — so the base pool must already be present in the instance before you build the meta
380
+ pool. If the base is a plain/main pool (e.g. `3pool`) it is always available right after `init`, but
381
+ if the base is itself a factory pool you must build it first.
382
+
383
+ Two helpers let the frontend resolve this without try/catch:
384
+
385
+ - **`curve.isBasePoolsReady(data): boolean`** — `true` if the pool can be built right now (always `true` for non-meta pools).
386
+ - **`curve.getRequiredBasePools(data): string[]`** — addresses of the base pools that still need to be built (empty ⇒ ready).
387
+
388
+ The base pool address is derived from the descriptor (`basePoolAddress`, or the last coin for crypto
389
+ meta pools). The frontend looks that address up in its own data, builds it, and re-checks:
390
+
391
+ ```ts
392
+ // Recursively make sure every base pool of `data` is initialized, then build the pool.
393
+ function ensurePool(data) {
394
+ if (!curve.isBasePoolsReady(data)) {
395
+ for (const baseAddress of curve.getRequiredBasePools(data)) {
396
+ const baseData = myDataSource.getByAddress(baseAddress); // your descriptor for the base pool
397
+ ensurePool(baseData); // base may itself be a meta pool
398
+ }
399
+ }
400
+ return curve.getPoolByData(data);
401
+ }
402
+
403
+ const pool = ensurePool(metaDescriptor);
404
+ ```
405
+
406
+ The typical frontend loop:
407
+
408
+ ```ts
409
+ if (!curve.isBasePoolsReady(desc)) {
410
+ const need = curve.getRequiredBasePools(desc); // e.g. ['0x383e…']
411
+ need.forEach((addr) => curve.getPoolByData(myDataSource.getByAddress(addr)));
412
+ // curve.isBasePoolsReady(desc) === true now
413
+ }
414
+ const pool = curve.getPoolByData(desc);
415
+ ```
416
+
417
+ As a safety net, if you call `getPoolByData` on a meta pool before its base is ready it throws an error
418
+ carrying the missing addresses on `error.missingBasePools`.
419
+
328
420
  ### Pool fields
329
421
  ```ts
330
422
  import curve from "@curvefi/api";
@@ -9,7 +9,7 @@ export const COINS_ETHEREUM = lowerCaseValues({
9
9
  susde: "0x9D39A5DE30e57443BfF2A8307A4256c8797A3497",
10
10
  usds: "0xdc035d45d973e3ec169d2276ddab16f1e407384f",
11
11
  susds: "0xa3931d71877c0e7a3148cb7eb4463524fec27fbd",
12
- reusd: "0x5086bf358635B81D8C47C66d1C8b9E567Db70c72",
12
+ reusd: "0x57aB1E0003F623289CD798B1824Be09a793e4Bec",
13
13
  sreusd: "0x557AB1e003951A73c12D16F0fEA8490E39C33C35",
14
14
  dola: "0x865377367054516e17014CcdED1e7d814EDC9ce4",
15
15
  sdola: "0xb45ad160634c528Cc3D2926d9807104FA3157305",
package/lib/curve.js CHANGED
@@ -298,7 +298,7 @@ export class Curve {
298
298
  ...this.getTricryptoFactoryPoolList(),
299
299
  ];
300
300
  };
301
- this.getPoolsData = () => (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.constants.POOLS_DATA), this.constants.FACTORY_POOLS_DATA), this.constants.CRVUSD_FACTORY_POOLS_DATA), this.constants.CRYPTO_FACTORY_POOLS_DATA), this.constants.STABLE_NG_FACTORY_POOLS_DATA), this.constants.TWOCRYPTO_FACTORY_POOLS_DATA), this.constants.TRICRYPTO_FACTORY_POOLS_DATA), this.constants.LLAMMAS_DATA));
301
+ this.getPoolsData = () => (Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, this.constants.POOLS_DATA), this.constants.FACTORY_POOLS_DATA), this.constants.CRVUSD_FACTORY_POOLS_DATA), this.constants.CRYPTO_FACTORY_POOLS_DATA), this.constants.STABLE_NG_FACTORY_POOLS_DATA), this.constants.TWOCRYPTO_FACTORY_POOLS_DATA), this.constants.TRICRYPTO_FACTORY_POOLS_DATA), this.constants.EXTERNAL_POOLS_DATA), this.constants.LLAMMAS_DATA));
302
302
  this.getGaugeImplementation = (factoryType) => this.constants.FACTORY_GAUGE_IMPLEMENTATIONS[factoryType] || this.constants.ZERO_ADDRESS;
303
303
  this.getNetworkConstants = () => {
304
304
  return this.constants;
@@ -340,6 +340,7 @@ export class Curve {
340
340
  TWOCRYPTO_FACTORY_POOLS_DATA: {},
341
341
  TRICRYPTO_FACTORY_POOLS_DATA: {},
342
342
  STABLE_NG_FACTORY_POOLS_DATA: {},
343
+ EXTERNAL_POOLS_DATA: {},
343
344
  BASE_POOLS: {},
344
345
  LLAMMAS_DATA: {},
345
346
  COINS: {},
@@ -379,6 +380,7 @@ export class Curve {
379
380
  TWOCRYPTO_FACTORY_POOLS_DATA: {},
380
381
  TRICRYPTO_FACTORY_POOLS_DATA: {},
381
382
  STABLE_NG_FACTORY_POOLS_DATA: {},
383
+ EXTERNAL_POOLS_DATA: {},
382
384
  BASE_POOLS: {},
383
385
  LLAMMAS_DATA: {},
384
386
  COINS: {},
@@ -389,6 +391,7 @@ export class Curve {
389
391
  };
390
392
  this.initContract = memoizedContract();
391
393
  this.initMulticallContract = memoizedMulticallContract();
394
+ let signerPromise = Promise.resolve(null);
392
395
  // JsonRpc provider
393
396
  if (providerType.toLowerCase() === 'JsonRpc'.toLowerCase()) {
394
397
  providerSettings = providerSettings;
@@ -405,22 +408,17 @@ export class Curve {
405
408
  this.provider = new ethers.JsonRpcProvider('http://localhost:8545/', undefined, jsonRpcApiProviderOptions);
406
409
  }
407
410
  if (providerSettings.privateKey) {
408
- this.signer = new ethers.Wallet(providerSettings.privateKey, this.provider);
411
+ signerPromise = Promise.resolve(new ethers.Wallet(providerSettings.privateKey, this.provider));
409
412
  }
410
413
  else if (!((_b = providerSettings.url) === null || _b === void 0 ? void 0 : _b.startsWith("https://rpc.gnosischain.com"))) {
411
- try {
412
- this.signer = yield this.provider.getSigner();
413
- }
414
- catch (_m) {
415
- this.signer = null;
416
- }
414
+ signerPromise = this.provider.getSigner().catch(() => null);
417
415
  }
418
416
  // Web3 provider
419
417
  }
420
418
  else if (providerType.toLowerCase() === 'Web3'.toLowerCase()) {
421
419
  providerSettings = providerSettings;
422
420
  this.provider = new ethers.BrowserProvider(providerSettings.externalProvider);
423
- this.signer = yield this.provider.getSigner();
421
+ signerPromise = this.provider.getSigner();
424
422
  // Infura provider
425
423
  }
426
424
  else if (providerType.toLowerCase() === 'Infura'.toLowerCase()) {
@@ -444,7 +442,11 @@ export class Curve {
444
442
  else {
445
443
  throw Error('Wrong providerType');
446
444
  }
447
- const network = this.isNoRPC ? { chainId: options.chainId, name: 'NoRPC' } : yield this.provider.getNetwork();
445
+ const [signer, network] = yield Promise.all([
446
+ signerPromise,
447
+ this.isNoRPC ? Promise.resolve({ chainId: options.chainId, name: 'NoRPC' }) : this.provider.getNetwork(),
448
+ ]);
449
+ this.signer = signer;
448
450
  console.log("CURVE-JS IS CONNECTED TO NETWORK:", { name: network.name.toUpperCase(), chainId: Number(network.chainId) });
449
451
  this.chainId = Number(network.chainId) === 133 || Number(network.chainId) === 31337 ? 1 : Number(network.chainId);
450
452
  this.isLiteChain = !(this.chainId in NETWORK_CONSTANTS);
@@ -485,22 +487,15 @@ export class Curve {
485
487
  this.constantOptions = {};
486
488
  }
487
489
  this.multicallProvider = new MulticallProvider(this.chainId, this.provider);
488
- if (this.signer) {
489
- try {
490
- this.signerAddress = yield this.signer.getAddress();
491
- }
492
- catch (_o) {
493
- this.signer = null;
494
- }
495
- }
496
- else {
497
- this.signerAddress = '';
498
- }
499
490
  this.feeData = { gasPrice: options.gasPrice, maxFeePerGas: options.maxFeePerGas, maxPriorityFeePerGas: options.maxPriorityFeePerGas };
500
491
  if (options.poolsData) {
501
492
  _setPoolsFromApi(this.constants.NETWORK_NAME, this.isLiteChain, options.poolsData);
502
493
  }
503
- yield this.updateFeeData();
494
+ const [signerAddress] = yield Promise.all([
495
+ this.signer ? this.signer.getAddress().catch(() => { this.signer = null; return ''; }) : Promise.resolve(''),
496
+ this.updateFeeData(),
497
+ ]);
498
+ this.signerAddress = signerAddress;
504
499
  for (const pool of Object.values(Object.assign(Object.assign({}, this.constants.POOLS_DATA), this.constants.LLAMMAS_DATA))) {
505
500
  this.setContract(pool.swap_address, pool.swap_abi);
506
501
  if (pool.token_address !== pool.swap_address) {
@@ -2,3 +2,4 @@ import { IDict, IFactoryPoolType, IPoolData, IPoolDataFromApi } from "../interfa
2
2
  import { type Curve } from "../curve";
3
3
  export declare const lowerCasePoolDataAddresses: (poolsData: IPoolDataFromApi[]) => IPoolDataFromApi[];
4
4
  export declare function getFactoryPoolsDataFromApi(this: Curve, factoryType: IFactoryPoolType): Promise<IDict<IPoolData>>;
5
+ export declare function buildFactoryPoolsData(this: Curve, factoryType: IFactoryPoolType, rawPoolListInput: IPoolDataFromApi[]): IDict<IPoolData>;
@@ -90,201 +90,209 @@ function setFactoryCoinsContracts(rawPoolList) {
90
90
  }
91
91
  export function getFactoryPoolsDataFromApi(factoryType) {
92
92
  return __awaiter(this, void 0, void 0, function* () {
93
- var _a;
94
93
  const network = this.constants.NETWORK_NAME;
95
- const is_ng = ["factory-stable-ng", "factory-twocrypto", "factory-tricrypto"].includes(factoryType);
96
- const isCrypto = ["factory-crypto", "factory-twocrypto", "factory-tricrypto"].includes(factoryType);
97
- const implementationABIDict = (_a = this.constants.STABLE_FACTORY_CONSTANTS.implementationABIDict) !== null && _a !== void 0 ? _a : {};
98
- let rawPoolList = lowerCasePoolDataAddresses((yield _getPoolsFromApi(network, factoryType, this.isLiteChain)).poolData);
99
- if (!isCrypto)
100
- rawPoolList = rawPoolList.filter((p) => is_ng || p.implementationAddress in implementationABIDict);
101
- // Filter duplications
102
- const mainAddresses = Object.values(this.constants.POOLS_DATA).map((pool) => pool.swap_address);
103
- rawPoolList = rawPoolList.filter((p) => !mainAddresses.includes(p.address));
104
- const swapABIs = isCrypto ? [] : rawPoolList.map((pool) => is_ng ?
105
- (pool.isMetaPool ? MetaStableSwapNGABI : PlainStableSwapNGABI) :
106
- implementationABIDict[pool.implementationAddress]);
107
- setFactorySwapContracts.call(this, rawPoolList, swapABIs, factoryType);
108
- if (factoryType === "factory-crypto")
109
- setCryptoFactoryTokenContracts.call(this, rawPoolList);
110
- setFactoryGaugeContracts.call(this, rawPoolList);
111
- setFactoryCoinsContracts.call(this, rawPoolList);
112
- setFactoryZapContracts.call(this, isCrypto);
113
- const FACTORY_POOLS_DATA = {};
114
- rawPoolList.forEach((pool, i) => {
115
- var _a, _b, _c, _d, _e, _f, _g, _h;
116
- const nativeToken = this.constants.NATIVE_TOKEN;
117
- const isETHEnabled = pool.implementationAddress === ((_a = this.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations) === null || _a === void 0 ? void 0 : _a.amm_native_transfers_enabled);
118
- let coinAddresses = pool.coins.map((c) => c.address);
119
- if (this.chainId === 137) {
120
- coinAddresses = coinAddresses.map((a) => a === "0x0000000000000000000000000000000000001010" ? nativeToken.wrappedAddress : a);
121
- }
122
- const coinNames = pool.coins.map((c) => c.symbol);
123
- const coinDecimals = pool.coins.map((c) => Number(c.decimals));
124
- if (isCrypto) {
125
- const wrappedCoinNames = pool.coins.map((c) => c.symbol === nativeToken.symbol ? nativeToken.wrappedSymbol : c.symbol);
126
- const underlyingCoinNames = pool.coins.map((c) => {
127
- if (factoryType === 'factory-twocrypto') {
128
- return c.symbol;
129
- }
130
- else if (factoryType === 'factory-tricrypto') {
131
- if (isETHEnabled) {
132
- return c.symbol === nativeToken.wrappedSymbol ? nativeToken.symbol : c.symbol;
133
- }
134
- else {
135
- return c.symbol;
136
- }
137
- }
138
- else {
94
+ const rawPoolList = lowerCasePoolDataAddresses((yield _getPoolsFromApi(network, factoryType, this.isLiteChain)).poolData);
95
+ return buildFactoryPoolsData.call(this, factoryType, rawPoolList);
96
+ });
97
+ }
98
+ export function buildFactoryPoolsData(factoryType, rawPoolListInput) {
99
+ var _a;
100
+ const is_ng = ["factory-stable-ng", "factory-twocrypto", "factory-tricrypto"].includes(factoryType);
101
+ const isCrypto = ["factory-crypto", "factory-twocrypto", "factory-tricrypto"].includes(factoryType);
102
+ const implementationABIDict = (_a = this.constants.STABLE_FACTORY_CONSTANTS.implementationABIDict) !== null && _a !== void 0 ? _a : {};
103
+ let rawPoolList = rawPoolListInput;
104
+ if (!isCrypto)
105
+ rawPoolList = rawPoolList.filter((p) => is_ng || p.implementationAddress in implementationABIDict);
106
+ // Filter duplications
107
+ const mainAddresses = Object.values(this.constants.POOLS_DATA).map((pool) => pool.swap_address);
108
+ rawPoolList = rawPoolList.filter((p) => !mainAddresses.includes(p.address));
109
+ const swapABIs = isCrypto ? [] : rawPoolList.map((pool) => is_ng ?
110
+ (pool.isMetaPool ? MetaStableSwapNGABI : PlainStableSwapNGABI) :
111
+ implementationABIDict[pool.implementationAddress]);
112
+ setFactorySwapContracts.call(this, rawPoolList, swapABIs, factoryType);
113
+ if (factoryType === "factory-crypto")
114
+ setCryptoFactoryTokenContracts.call(this, rawPoolList);
115
+ setFactoryGaugeContracts.call(this, rawPoolList);
116
+ setFactoryCoinsContracts.call(this, rawPoolList);
117
+ setFactoryZapContracts.call(this, isCrypto);
118
+ const FACTORY_POOLS_DATA = {};
119
+ rawPoolList.forEach((pool, i) => {
120
+ var _a, _b, _c, _d, _e, _f, _g, _h;
121
+ const nativeToken = this.constants.NATIVE_TOKEN;
122
+ const isETHEnabled = pool.implementationAddress === ((_a = this.constants.CRYPTO_FACTORY_CONSTANTS.tricryptoDeployImplementations) === null || _a === void 0 ? void 0 : _a.amm_native_transfers_enabled);
123
+ let coinAddresses = pool.coins.map((c) => c.address);
124
+ if (this.chainId === 137) {
125
+ coinAddresses = coinAddresses.map((a) => a === "0x0000000000000000000000000000000000001010" ? nativeToken.wrappedAddress : a);
126
+ }
127
+ const coinNames = pool.coins.map((c) => c.symbol);
128
+ const coinDecimals = pool.coins.map((c) => Number(c.decimals));
129
+ if (isCrypto) {
130
+ const wrappedCoinNames = pool.coins.map((c) => c.symbol === nativeToken.symbol ? nativeToken.wrappedSymbol : c.symbol);
131
+ const underlyingCoinNames = pool.coins.map((c) => {
132
+ if (factoryType === 'factory-twocrypto') {
133
+ return c.symbol;
134
+ }
135
+ else if (factoryType === 'factory-tricrypto') {
136
+ if (isETHEnabled) {
139
137
  return c.symbol === nativeToken.wrappedSymbol ? nativeToken.symbol : c.symbol;
140
138
  }
141
- });
142
- const underlyingCoinAddresses = coinAddresses.map((addr) => {
143
- if (factoryType === 'factory-twocrypto') {
144
- return addr;
145
- }
146
- else if (factoryType === 'factory-tricrypto') {
147
- if (isETHEnabled) {
148
- return addr === nativeToken.wrappedAddress ? nativeToken.address : addr;
149
- }
150
- else {
151
- return addr;
152
- }
153
- }
154
139
  else {
155
- return addr === nativeToken.wrappedAddress ? nativeToken.address : addr;
140
+ return c.symbol;
156
141
  }
157
- });
158
- const isPlain = underlyingCoinNames.toString() === wrappedCoinNames.toString();
159
- const lpTokenBasePoolIdDict = (_b = this.constants.CRYPTO_FACTORY_CONSTANTS.lpTokenBasePoolIdDict) !== null && _b !== void 0 ? _b : {};
160
- const basePoolIdZapDict = (_c = this.constants.CRYPTO_FACTORY_CONSTANTS.basePoolIdZapDict) !== null && _c !== void 0 ? _c : {};
161
- const basePoolId = lpTokenBasePoolIdDict[coinAddresses[1]];
162
- if (factoryType !== "factory-tricrypto" && factoryType !== "factory-twocrypto" && basePoolId) { // isMeta
163
- const allPoolsData = Object.assign(Object.assign({}, this.constants.POOLS_DATA), FACTORY_POOLS_DATA);
164
- const basePoolCoinNames = [...allPoolsData[basePoolId].underlying_coins];
165
- const basePoolCoinAddresses = [...allPoolsData[basePoolId].underlying_coin_addresses];
166
- const basePoolDecimals = [...allPoolsData[basePoolId].underlying_decimals];
167
- const basePoolZap = basePoolIdZapDict[basePoolId];
168
- this.constants.BASE_POOLS[basePoolId] = this.constants.BASE_POOLS[basePoolId] ? this.constants.BASE_POOLS[basePoolId] + 1 : 1;
169
- FACTORY_POOLS_DATA[pool.id] = {
170
- name: getPoolName(pool.name),
171
- full_name: pool.name,
172
- symbol: pool.symbol,
173
- reference_asset: "CRYPTO",
174
- swap_address: pool.address,
175
- token_address: pool.lpTokenAddress,
176
- gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS,
177
- deposit_address: basePoolZap.address,
178
- is_meta: true,
179
- is_crypto: true,
180
- is_factory: true,
181
- base_pool: basePoolId,
182
- underlying_coins: [underlyingCoinNames[0], ...basePoolCoinNames],
183
- wrapped_coins: wrappedCoinNames,
184
- underlying_coin_addresses: [underlyingCoinAddresses[0], ...basePoolCoinAddresses],
185
- wrapped_coin_addresses: coinAddresses,
186
- underlying_decimals: [coinDecimals[0], ...basePoolDecimals],
187
- wrapped_decimals: coinDecimals,
188
- swap_abi: cryptoFactorySwapABI,
189
- gauge_abi: this.chainId === 1 ? factoryGaugeABI : gaugeChildABI,
190
- deposit_abi: basePoolZap.ABI,
191
- in_api: true,
192
- is_ng,
193
- };
194
142
  }
195
143
  else {
196
- FACTORY_POOLS_DATA[pool.id] = {
197
- name: factoryType === "factory-tricrypto" ? pool.name : getPoolName(pool.name),
198
- full_name: pool.name,
199
- symbol: pool.symbol,
200
- reference_asset: "CRYPTO",
201
- swap_address: pool.address,
202
- token_address: pool.lpTokenAddress,
203
- gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS,
204
- is_crypto: true,
205
- is_plain: isPlain,
206
- is_factory: true,
207
- underlying_coins: underlyingCoinNames,
208
- wrapped_coins: wrappedCoinNames,
209
- underlying_coin_addresses: underlyingCoinAddresses,
210
- wrapped_coin_addresses: coinAddresses,
211
- underlying_decimals: coinDecimals,
212
- wrapped_decimals: coinDecimals,
213
- swap_abi: getSwapAbiByFactoryType.call(this, factoryType, pool),
214
- gauge_abi: this.chainId === 1 ? factoryGaugeABI : gaugeChildABI,
215
- in_api: true,
216
- is_ng,
217
- };
144
+ return c.symbol === nativeToken.wrappedSymbol ? nativeToken.symbol : c.symbol;
218
145
  }
219
- }
220
- else if (pool.isMetaPool) {
221
- const allPoolsData = Object.assign(Object.assign({}, this.constants.POOLS_DATA), FACTORY_POOLS_DATA);
222
- const basePoolId = getPoolIdByAddress.call(this, rawPoolList, pool.basePoolAddress);
223
- this.constants.BASE_POOLS[basePoolId] = this.constants.BASE_POOLS[basePoolId] ? this.constants.BASE_POOLS[basePoolId] + 1 : 1;
224
- const basePoolCoinNames = (_d = allPoolsData[basePoolId]) === null || _d === void 0 ? void 0 : _d.underlying_coins;
225
- const basePoolCoinAddresses = (_e = allPoolsData[basePoolId]) === null || _e === void 0 ? void 0 : _e.underlying_coin_addresses;
226
- const basePoolDecimals = (_f = allPoolsData[basePoolId]) === null || _f === void 0 ? void 0 : _f.underlying_decimals;
227
- const basePoolIdZapDict = (_g = this.constants.STABLE_FACTORY_CONSTANTS.basePoolIdZapDict) !== null && _g !== void 0 ? _g : {};
228
- let deposit_address = (_h = this.constants.STABLE_FACTORY_CONSTANTS.stableNgBasePoolZap) !== null && _h !== void 0 ? _h : this.constants.ZERO_ADDRESS;
229
- let deposit_abi = StableNgBasePoolZapABI;
230
- if (isStableNgPool(basePoolId)) {
231
- this.setContract(deposit_address, StableNgBasePoolZapABI);
146
+ });
147
+ const underlyingCoinAddresses = coinAddresses.map((addr) => {
148
+ if (factoryType === 'factory-twocrypto') {
149
+ return addr;
150
+ }
151
+ else if (factoryType === 'factory-tricrypto') {
152
+ if (isETHEnabled) {
153
+ return addr === nativeToken.wrappedAddress ? nativeToken.address : addr;
154
+ }
155
+ else {
156
+ return addr;
157
+ }
232
158
  }
233
159
  else {
234
- deposit_address = basePoolIdZapDict[basePoolId].address;
235
- deposit_abi = basePoolIdZapDict[basePoolId].ABI;
160
+ return addr === nativeToken.wrappedAddress ? nativeToken.address : addr;
236
161
  }
162
+ });
163
+ const isPlain = underlyingCoinNames.toString() === wrappedCoinNames.toString();
164
+ const lpTokenBasePoolIdDict = (_b = this.constants.CRYPTO_FACTORY_CONSTANTS.lpTokenBasePoolIdDict) !== null && _b !== void 0 ? _b : {};
165
+ const basePoolIdZapDict = (_c = this.constants.CRYPTO_FACTORY_CONSTANTS.basePoolIdZapDict) !== null && _c !== void 0 ? _c : {};
166
+ const basePoolId = lpTokenBasePoolIdDict[coinAddresses[1]];
167
+ if (factoryType !== "factory-tricrypto" && factoryType !== "factory-twocrypto" && basePoolId) { // isMeta
168
+ const allPoolsData = Object.assign(Object.assign({}, this.getPoolsData()), FACTORY_POOLS_DATA);
169
+ if (!allPoolsData[basePoolId])
170
+ throw new Error(`Base pool "${basePoolId}" of meta pool ${pool.id} (${pool.address}) is not loaded. Build or fetch the base pool before this one.`);
171
+ const basePoolCoinNames = [...allPoolsData[basePoolId].underlying_coins];
172
+ const basePoolCoinAddresses = [...allPoolsData[basePoolId].underlying_coin_addresses];
173
+ const basePoolDecimals = [...allPoolsData[basePoolId].underlying_decimals];
174
+ const basePoolZap = basePoolIdZapDict[basePoolId];
175
+ this.constants.BASE_POOLS[basePoolId] = this.constants.BASE_POOLS[basePoolId] ? this.constants.BASE_POOLS[basePoolId] + 1 : 1;
237
176
  FACTORY_POOLS_DATA[pool.id] = {
238
177
  name: getPoolName(pool.name),
239
178
  full_name: pool.name,
240
179
  symbol: pool.symbol,
241
- reference_asset: assetTypeNameHandler(pool.assetTypeName),
180
+ reference_asset: "CRYPTO",
242
181
  swap_address: pool.address,
243
- token_address: pool.address,
182
+ token_address: pool.lpTokenAddress,
244
183
  gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS,
245
- deposit_address,
246
- implementation_address: pool.implementationAddress, // Only for testing
184
+ deposit_address: basePoolZap.address,
247
185
  is_meta: true,
186
+ is_crypto: true,
248
187
  is_factory: true,
249
188
  base_pool: basePoolId,
250
- underlying_coins: [coinNames[0], ...basePoolCoinNames],
251
- wrapped_coins: coinNames,
252
- underlying_coin_addresses: [coinAddresses[0], ...basePoolCoinAddresses],
189
+ underlying_coins: [underlyingCoinNames[0], ...basePoolCoinNames],
190
+ wrapped_coins: wrappedCoinNames,
191
+ underlying_coin_addresses: [underlyingCoinAddresses[0], ...basePoolCoinAddresses],
253
192
  wrapped_coin_addresses: coinAddresses,
254
193
  underlying_decimals: [coinDecimals[0], ...basePoolDecimals],
255
194
  wrapped_decimals: coinDecimals,
256
- swap_abi: swapABIs[i],
195
+ swap_abi: cryptoFactorySwapABI,
257
196
  gauge_abi: this.chainId === 1 ? factoryGaugeABI : gaugeChildABI,
258
- deposit_abi,
197
+ deposit_abi: basePoolZap.ABI,
259
198
  in_api: true,
260
199
  is_ng,
261
200
  };
262
201
  }
263
202
  else {
264
203
  FACTORY_POOLS_DATA[pool.id] = {
265
- name: getPoolName(pool.name),
204
+ name: factoryType === "factory-tricrypto" ? pool.name : getPoolName(pool.name),
266
205
  full_name: pool.name,
267
206
  symbol: pool.symbol,
268
- reference_asset: assetTypeNameHandler(pool.assetTypeName),
207
+ reference_asset: "CRYPTO",
269
208
  swap_address: pool.address,
270
- token_address: pool.address,
209
+ token_address: pool.lpTokenAddress,
271
210
  gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS,
272
- implementation_address: pool.implementationAddress, // Only for testing
273
- is_plain: true,
211
+ is_crypto: true,
212
+ is_plain: isPlain,
274
213
  is_factory: true,
275
- underlying_coins: coinNames,
276
- wrapped_coins: coinNames,
277
- underlying_coin_addresses: coinAddresses,
214
+ underlying_coins: underlyingCoinNames,
215
+ wrapped_coins: wrappedCoinNames,
216
+ underlying_coin_addresses: underlyingCoinAddresses,
278
217
  wrapped_coin_addresses: coinAddresses,
279
218
  underlying_decimals: coinDecimals,
280
219
  wrapped_decimals: coinDecimals,
281
- swap_abi: swapABIs[i],
220
+ swap_abi: getSwapAbiByFactoryType.call(this, factoryType, pool),
282
221
  gauge_abi: this.chainId === 1 ? factoryGaugeABI : gaugeChildABI,
283
222
  in_api: true,
284
223
  is_ng,
285
224
  };
286
225
  }
287
- });
288
- return FACTORY_POOLS_DATA;
226
+ }
227
+ else if (pool.isMetaPool) {
228
+ const allPoolsData = Object.assign(Object.assign({}, this.getPoolsData()), FACTORY_POOLS_DATA);
229
+ const basePoolId = getPoolIdByAddress.call(this, rawPoolList, pool.basePoolAddress);
230
+ if (!allPoolsData[basePoolId])
231
+ throw new Error(`Base pool "${pool.basePoolAddress}" of meta pool ${pool.id} (${pool.address}) is not loaded. Build or fetch the base pool before this one.`);
232
+ this.constants.BASE_POOLS[basePoolId] = this.constants.BASE_POOLS[basePoolId] ? this.constants.BASE_POOLS[basePoolId] + 1 : 1;
233
+ const basePoolCoinNames = (_d = allPoolsData[basePoolId]) === null || _d === void 0 ? void 0 : _d.underlying_coins;
234
+ const basePoolCoinAddresses = (_e = allPoolsData[basePoolId]) === null || _e === void 0 ? void 0 : _e.underlying_coin_addresses;
235
+ const basePoolDecimals = (_f = allPoolsData[basePoolId]) === null || _f === void 0 ? void 0 : _f.underlying_decimals;
236
+ const basePoolIdZapDict = (_g = this.constants.STABLE_FACTORY_CONSTANTS.basePoolIdZapDict) !== null && _g !== void 0 ? _g : {};
237
+ let deposit_address = (_h = this.constants.STABLE_FACTORY_CONSTANTS.stableNgBasePoolZap) !== null && _h !== void 0 ? _h : this.constants.ZERO_ADDRESS;
238
+ let deposit_abi = StableNgBasePoolZapABI;
239
+ if (isStableNgPool(basePoolId)) {
240
+ this.setContract(deposit_address, StableNgBasePoolZapABI);
241
+ }
242
+ else {
243
+ deposit_address = basePoolIdZapDict[basePoolId].address;
244
+ deposit_abi = basePoolIdZapDict[basePoolId].ABI;
245
+ }
246
+ FACTORY_POOLS_DATA[pool.id] = {
247
+ name: getPoolName(pool.name),
248
+ full_name: pool.name,
249
+ symbol: pool.symbol,
250
+ reference_asset: assetTypeNameHandler(pool.assetTypeName),
251
+ swap_address: pool.address,
252
+ token_address: pool.address,
253
+ gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS,
254
+ deposit_address,
255
+ implementation_address: pool.implementationAddress, // Only for testing
256
+ is_meta: true,
257
+ is_factory: true,
258
+ base_pool: basePoolId,
259
+ underlying_coins: [coinNames[0], ...basePoolCoinNames],
260
+ wrapped_coins: coinNames,
261
+ underlying_coin_addresses: [coinAddresses[0], ...basePoolCoinAddresses],
262
+ wrapped_coin_addresses: coinAddresses,
263
+ underlying_decimals: [coinDecimals[0], ...basePoolDecimals],
264
+ wrapped_decimals: coinDecimals,
265
+ swap_abi: swapABIs[i],
266
+ gauge_abi: this.chainId === 1 ? factoryGaugeABI : gaugeChildABI,
267
+ deposit_abi,
268
+ in_api: true,
269
+ is_ng,
270
+ };
271
+ }
272
+ else {
273
+ FACTORY_POOLS_DATA[pool.id] = {
274
+ name: getPoolName(pool.name),
275
+ full_name: pool.name,
276
+ symbol: pool.symbol,
277
+ reference_asset: assetTypeNameHandler(pool.assetTypeName),
278
+ swap_address: pool.address,
279
+ token_address: pool.address,
280
+ gauge_address: pool.gaugeAddress ? pool.gaugeAddress : this.constants.ZERO_ADDRESS,
281
+ implementation_address: pool.implementationAddress, // Only for testing
282
+ is_plain: true,
283
+ is_factory: true,
284
+ underlying_coins: coinNames,
285
+ wrapped_coins: coinNames,
286
+ underlying_coin_addresses: coinAddresses,
287
+ wrapped_coin_addresses: coinAddresses,
288
+ underlying_decimals: coinDecimals,
289
+ wrapped_decimals: coinDecimals,
290
+ swap_abi: swapABIs[i],
291
+ gauge_abi: this.chainId === 1 ? factoryGaugeABI : gaugeChildABI,
292
+ in_api: true,
293
+ is_ng,
294
+ };
295
+ }
289
296
  });
297
+ return FACTORY_POOLS_DATA;
290
298
  }
package/lib/index.d.ts CHANGED
@@ -43,6 +43,9 @@ export declare const createCurve: () => {
43
43
  PoolTemplate: typeof PoolTemplate;
44
44
  getBasePools: () => Promise<import("./interfaces.js").IBasePoolShortItem[]>;
45
45
  getPool: (poolIdOrAddress: string) => PoolTemplate;
46
+ getPoolByData: (data: import("./interfaces.js").IExternalPoolData) => PoolTemplate;
47
+ getRequiredBasePools: (data: import("./interfaces.js").IExternalPoolData) => string[];
48
+ isBasePoolsReady: (data: import("./interfaces.js").IExternalPoolData) => boolean;
46
49
  getUsdRate: (coin: string) => Promise<number>;
47
50
  getGasPriceFromL1: () => Promise<number>;
48
51
  getGasPriceFromL2: () => Promise<number>;
@@ -377,6 +380,9 @@ declare const _default: {
377
380
  PoolTemplate: typeof PoolTemplate;
378
381
  getBasePools: () => Promise<import("./interfaces.js").IBasePoolShortItem[]>;
379
382
  getPool: (poolIdOrAddress: string) => PoolTemplate;
383
+ getPoolByData: (data: import("./interfaces.js").IExternalPoolData) => PoolTemplate;
384
+ getRequiredBasePools: (data: import("./interfaces.js").IExternalPoolData) => string[];
385
+ isBasePoolsReady: (data: import("./interfaces.js").IExternalPoolData) => boolean;
380
386
  getUsdRate: (coin: string) => Promise<number>;
381
387
  getGasPriceFromL1: () => Promise<number>;
382
388
  getGasPriceFromL2: () => Promise<number>;
package/lib/index.js CHANGED
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { PoolTemplate, getPool } from "./pools/index.js";
10
+ import { PoolTemplate, getPool, getPoolByData, getRequiredBasePools, isBasePoolsReady } from "./pools/index.js";
11
11
  import { getUserPoolListByLiquidity, getUserPoolListByClaimable, getUserPoolList, getUserLiquidityUSD, getUserClaimable, } from "./pools/utils.js";
12
12
  import { getBestRouteAndOutput, getArgs, swapExpected, swapRequired, swapPriceImpact, swapIsApproved, swapApproveEstimateGas, swapApprove, swapPopulateApprove, swapEstimateGas, swap, populateSwap, getSwappedAmount, approveFromCalldata, approveFromCalldataEstimateGas, swapFromCalldata, swapFromCalldataEstimateGas, setRouterBlacklist, } from "./router.js";
13
13
  import { isSupported, assertIsSupported, allowedToBridge, bridgeCost, bridgeIsApproved, bridgeApproveEstimateGas, bridgeApprove, bridgeEstimateGas, bridge, getSupportedNetworks, } from "./bridge.js";
@@ -43,6 +43,9 @@ export const createCurve = () => {
43
43
  PoolTemplate: PoolTemplate.bind(_curve),
44
44
  getBasePools: getBasePools.bind(_curve),
45
45
  getPool: getPool.bind(_curve),
46
+ getPoolByData: getPoolByData.bind(_curve),
47
+ getRequiredBasePools: getRequiredBasePools.bind(_curve),
48
+ isBasePoolsReady: isBasePoolsReady.bind(_curve),
46
49
  getUsdRate: getUsdRate.bind(_curve),
47
50
  getGasPriceFromL1: getGasPriceFromL1.bind(_curve),
48
51
  getGasPriceFromL2: getGasPriceFromL2.bind(_curve),
@@ -81,6 +81,7 @@ export interface INetworkConstants {
81
81
  CRYPTO_FACTORY_POOLS_DATA: IDict<IPoolData>;
82
82
  TWOCRYPTO_FACTORY_POOLS_DATA: IDict<IPoolData>;
83
83
  TRICRYPTO_FACTORY_POOLS_DATA: IDict<IPoolData>;
84
+ EXTERNAL_POOLS_DATA?: IDict<IPoolData>;
84
85
  BASE_POOLS: IDict<number>;
85
86
  LLAMMAS_DATA: IDict<IPoolData>;
86
87
  COINS: IDict<string>;
@@ -170,6 +171,25 @@ export interface IPoolDataShort {
170
171
  id: string;
171
172
  address: string;
172
173
  }
174
+ export interface IExternalPoolData {
175
+ poolType: IFactoryPoolType;
176
+ address: string;
177
+ coins: {
178
+ address: string;
179
+ symbol: string;
180
+ decimals: number | string;
181
+ }[];
182
+ id?: string;
183
+ name?: string;
184
+ symbol?: string;
185
+ lpTokenAddress?: string;
186
+ gaugeAddress?: string;
187
+ implementationAddress?: string;
188
+ isMetaPool?: boolean;
189
+ basePoolAddress?: string;
190
+ assetTypeName?: string;
191
+ gaugeRewards?: IRewardFromApi[];
192
+ }
173
193
  export type IRoutePoolData = Pick<IPoolData, 'is_lending' | 'wrapped_coin_addresses' | 'underlying_coin_addresses' | 'token_address'>;
174
194
  export interface IExtendedPoolDataFromApi {
175
195
  poolData: IPoolDataFromApi[];
@@ -1,3 +1,3 @@
1
- import { getPool } from "./poolConstructor.js";
1
+ import { getPool, getPoolByData, getRequiredBasePools, isBasePoolsReady } from "./poolConstructor.js";
2
2
  import { PoolTemplate } from "./PoolTemplate.js";
3
- export { getPool, PoolTemplate, };
3
+ export { getPool, getPoolByData, getRequiredBasePools, isBasePoolsReady, PoolTemplate, };
@@ -1,3 +1,3 @@
1
- import { getPool } from "./poolConstructor.js";
1
+ import { getPool, getPoolByData, getRequiredBasePools, isBasePoolsReady } from "./poolConstructor.js";
2
2
  import { PoolTemplate } from "./PoolTemplate.js";
3
- export { getPool, PoolTemplate, };
3
+ export { getPool, getPoolByData, getRequiredBasePools, isBasePoolsReady, PoolTemplate, };
@@ -1,3 +1,7 @@
1
1
  import { type Curve } from "../curve.js";
2
2
  import { PoolTemplate } from "./PoolTemplate.js";
3
+ import type { IExternalPoolData } from "../interfaces.js";
3
4
  export declare function getPool(this: Curve, poolIdOrAddress: string): PoolTemplate;
5
+ export declare function getRequiredBasePools(this: Curve, data: IExternalPoolData): string[];
6
+ export declare function isBasePoolsReady(this: Curve, data: IExternalPoolData): boolean;
7
+ export declare function getPoolByData(this: Curve, data: IExternalPoolData): PoolTemplate;
@@ -16,6 +16,8 @@ import { swapCryptoMetaFactoryMixin, swapMetaFactoryMixin, swapMixin, swapTricry
16
16
  import { swapWrappedExpectedAndApproveMixin, swapWrappedMixin, swapWrappedRequiredMixin, swapWrappedTricrypto2Mixin, } from "./mixins/swapWrappedMixins.js";
17
17
  import { findAbiSignature, getCountArgsOfMethodByAbi, getPoolIdBySwapAddress } from "../utils.js";
18
18
  import { StatsPool } from "./subClasses/statsPool.js";
19
+ import { lowerCasePoolDataAddresses } from "../constants/utils.js";
20
+ import { buildFactoryPoolsData, lowerCasePoolDataAddresses as lowerCaseApiPoolAddresses } from "../factory/factory-api.js";
19
21
  export function getPool(poolIdOrAddress) {
20
22
  const poolId = poolIdOrAddress.toLowerCase().startsWith('0x') ? getPoolIdBySwapAddress.call(this, poolIdOrAddress.toLowerCase()) : poolIdOrAddress;
21
23
  if (!poolId) {
@@ -225,3 +227,59 @@ export function getPool(poolIdOrAddress) {
225
227
  }
226
228
  return new Pool(poolId, this);
227
229
  }
230
+ function resolveBasePoolAddress(data) {
231
+ if (!data.isMetaPool)
232
+ return null;
233
+ if (data.basePoolAddress)
234
+ return data.basePoolAddress.toLowerCase();
235
+ if (data.coins.length)
236
+ return data.coins[data.coins.length - 1].address.toLowerCase();
237
+ return null;
238
+ }
239
+ function isPoolLoaded(address) {
240
+ const a = address.toLowerCase();
241
+ return Object.values(this.getPoolsData()).some((pd) => pd.swap_address.toLowerCase() === a || pd.token_address.toLowerCase() === a);
242
+ }
243
+ export function getRequiredBasePools(data) {
244
+ const base = resolveBasePoolAddress(data);
245
+ return base && !isPoolLoaded.call(this, base) ? [base] : [];
246
+ }
247
+ export function isBasePoolsReady(data) {
248
+ return getRequiredBasePools.call(this, data).length === 0;
249
+ }
250
+ export function getPoolByData(data) {
251
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
252
+ const id = ((_a = data.id) !== null && _a !== void 0 ? _a : data.address).toLowerCase();
253
+ const missingBasePools = getRequiredBasePools.call(this, data);
254
+ if (missingBasePools.length) {
255
+ const err = new Error(`Pool ${id} is a meta pool whose base pool ${missingBasePools.join(", ")} is not initialized. Call getPoolByData for the base pool(s) first.`);
256
+ err.missingBasePools = missingBasePools;
257
+ throw err;
258
+ }
259
+ const rawPool = {
260
+ id,
261
+ name: (_b = data.name) !== null && _b !== void 0 ? _b : id,
262
+ symbol: (_c = data.symbol) !== null && _c !== void 0 ? _c : "",
263
+ assetTypeName: (_d = data.assetTypeName) !== null && _d !== void 0 ? _d : "unknown",
264
+ address: data.address,
265
+ isMetaPool: (_e = data.isMetaPool) !== null && _e !== void 0 ? _e : false,
266
+ basePoolAddress: data.basePoolAddress,
267
+ lpTokenAddress: (_f = data.lpTokenAddress) !== null && _f !== void 0 ? _f : data.address,
268
+ gaugeAddress: data.gaugeAddress,
269
+ implementation: "",
270
+ implementationAddress: (_g = data.implementationAddress) !== null && _g !== void 0 ? _g : "",
271
+ coins: data.coins.map((c) => ({ address: c.address, symbol: c.symbol, decimals: String(c.decimals), usdPrice: 0 })),
272
+ gaugeRewards: (_h = data.gaugeRewards) !== null && _h !== void 0 ? _h : [],
273
+ usdTotal: 0,
274
+ totalSupply: 0,
275
+ amplificationCoefficient: "0",
276
+ gaugeCrvApy: [null, null],
277
+ };
278
+ const rawPoolList = lowerCaseApiPoolAddresses([rawPool]);
279
+ const builtData = lowerCasePoolDataAddresses(buildFactoryPoolsData.call(this, data.poolType, rawPoolList));
280
+ if (!builtData[id]) {
281
+ throw new Error(`Could not resolve ABI for pool ${id} (poolType=${data.poolType}, implementation=${(_j = data.implementationAddress) !== null && _j !== void 0 ? _j : "none"}). The implementation is unknown to curve for this poolType.`);
282
+ }
283
+ this.constants.EXTERNAL_POOLS_DATA = Object.assign(Object.assign({}, this.constants.EXTERNAL_POOLS_DATA), builtData);
284
+ return getPool.call(this, id);
285
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@curvefi/api",
3
- "version": "2.69.17",
3
+ "version": "2.70.0",
4
4
  "description": "JavaScript library for curve.finance",
5
5
  "main": "lib/index.js",
6
6
  "author": "Macket",