@alephium/powfi-sdk 0.0.1-rc.2 → 0.0.1-rc.21
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 +97 -1
- package/clmm/artifacts/BitmapWord.ral.json +1 -1
- package/clmm/artifacts/BitmapWordDeployer.ral.json +1 -1
- package/clmm/artifacts/CreateConfig.ral.json +1 -1
- package/clmm/artifacts/CreateLiquidPool.ral.json +1 -1
- package/clmm/artifacts/DexAccount.ral.json +1 -1
- package/clmm/artifacts/LiquidityAmountsTest.ral.json +1 -1
- package/clmm/artifacts/LiquidityManagmentTest.ral.json +1 -1
- package/clmm/artifacts/Pool.ral.json +14 -5
- package/clmm/artifacts/PoolConfig.ral.json +1 -1
- package/clmm/artifacts/PoolFactory.ral.json +1 -1
- package/clmm/artifacts/PoolRouterDemo.ral.json +2 -2
- package/clmm/artifacts/PoolUser.ral.json +1 -1
- package/clmm/artifacts/Position.ral.json +18 -4
- package/clmm/artifacts/PositionManager.ral.json +1 -1
- package/clmm/artifacts/SwapWithoutAccount.ral.json +2 -2
- package/clmm/artifacts/TestToken.ral.json +1 -1
- package/clmm/artifacts/Tick.ral.json +1 -1
- package/clmm/artifacts/TickBitmapTest.ral.json +1 -1
- package/clmm/artifacts/ts/Pool.ts +14 -2
- package/clmm/artifacts/ts/Position.ts +37 -3
- package/cpmm/artifacts/scripts/CreatePairAndAddLiquidity.ral.json +6 -3
- package/cpmm/artifacts/ts/scripts.ts +1 -0
- package/lib/index.d.mts +242 -119
- package/lib/index.d.ts +242 -119
- package/lib/index.js +627 -329
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +628 -329
- package/lib/index.mjs.map +1 -1
- package/package.json +9 -8
- package/src/clmm/clmm.ts +70 -47
- package/src/clmm/liquidity.ts +1 -1
- package/src/clmm/pool.ts +15 -17
- package/src/clmm/tick.ts +21 -33
- package/src/clmm/types.ts +12 -12
- package/src/common/error.ts +7 -7
- package/src/common/types.ts +1 -1
- package/src/cpmm/cpmm.ts +135 -103
- package/src/cpmm/types.ts +48 -42
- package/src/index.ts +1 -1
- package/src/moduleBase.ts +3 -3
- package/src/{zeta.ts → powfi.ts} +5 -5
- package/src/staking/staking.ts +31 -24
- package/src/token/token.ts +2 -2
- package/staking/artifacts/AlphUnstakeVault.ral.json +13 -3
- package/staking/artifacts/XAlphStakeVault.ral.json +1 -1
- package/staking/artifacts/XAlphToken.ral.json +139 -6
- package/staking/artifacts/XAlphUnlockAndStartUnstake.ral.json +2 -2
- package/staking/artifacts/examples/GovernanceDemo.ral.json +1 -1
- package/staking/artifacts/examples/RewardSharingVault.ral.json +1 -1
- package/staking/artifacts/ts/AlphUnstakeVault.ts +40 -1
- package/staking/artifacts/ts/XAlphToken.ts +209 -8
- package/staking/artifacts/ts/scripts.ts +0 -10
- package/staking/artifacts/utils/FullMathTest.ral.json +1 -1
- package/staking/artifacts/utils/TestDynamicArrayByteVec32.ral.json +1 -1
- package/staking/artifacts/utils/TestDynamicSortedArrayForU256.ral.json +1 -1
- package/staking/artifacts/utils/TestMerkleProof.ral.json +1 -1
- package/staking/deployments/.deployments.devnet.json +45 -44
- package/staking/deployments/.deployments.testnet.json +23 -23
- package/staking/artifacts/AlphStakeAndLock.ral.json +0 -31
package/src/cpmm/cpmm.ts
CHANGED
|
@@ -15,9 +15,10 @@ import {
|
|
|
15
15
|
RemoveLiquidity,
|
|
16
16
|
CreatePair,
|
|
17
17
|
CreatePairAndAddLiquidity,
|
|
18
|
+
TokenPairFactory,
|
|
18
19
|
} from 'cpmm/artifacts/ts';
|
|
19
20
|
import { loadDeployments } from 'cpmm/artifacts/ts/deployments';
|
|
20
|
-
import type {
|
|
21
|
+
import type { TokenInfo } from '@alephium/token-list';
|
|
21
22
|
import { sortTokens } from '../common/utils';
|
|
22
23
|
import { MAX_PRICE_IMPACT } from './constants';
|
|
23
24
|
import {
|
|
@@ -26,19 +27,20 @@ import {
|
|
|
26
27
|
PoolNotFoundError,
|
|
27
28
|
} from '../common/error';
|
|
28
29
|
import type {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
RemoveLiquidityParams,
|
|
34
|
-
RemoveLiquidityDetails,
|
|
35
|
-
ClaimableAmounts,
|
|
36
|
-
CreatePoolParams,
|
|
37
|
-
ComputeSwapParams,
|
|
38
|
-
ComputeLiquidityParams,
|
|
30
|
+
CpmmAddLiquidityQuote,
|
|
31
|
+
CpmmAddLiquidityQuoteParams,
|
|
32
|
+
CpmmAddLiquidityRequest,
|
|
33
|
+
CpmmClaimableAmounts,
|
|
39
34
|
CpmmConfig,
|
|
35
|
+
CpmmCreatePoolRequest,
|
|
36
|
+
CpmmPoolContractState,
|
|
37
|
+
CpmmRemoveLiquidityQuote,
|
|
38
|
+
CpmmRemoveLiquidityRequest,
|
|
39
|
+
CpmmSwapQuote,
|
|
40
|
+
CpmmSwapQuoteParams,
|
|
41
|
+
CpmmSwapRequest,
|
|
40
42
|
} from './types';
|
|
41
|
-
import type {
|
|
43
|
+
import type { Powfi } from '../powfi';
|
|
42
44
|
import ModuleBase from '../moduleBase';
|
|
43
45
|
import BigNumber from 'bignumber.js';
|
|
44
46
|
import { MathUtil } from '../common/math';
|
|
@@ -49,7 +51,7 @@ import { InsufficientLiquidityError } from '../common/error';
|
|
|
49
51
|
export class CpmmModule extends ModuleBase {
|
|
50
52
|
private config: CpmmConfig;
|
|
51
53
|
|
|
52
|
-
constructor(scope:
|
|
54
|
+
constructor(scope: Powfi) {
|
|
53
55
|
super({ scope, moduleName: 'CpmmModule' });
|
|
54
56
|
|
|
55
57
|
this.config = this.getCpmmConfig();
|
|
@@ -108,19 +110,22 @@ export class CpmmModule extends ModuleBase {
|
|
|
108
110
|
});
|
|
109
111
|
}
|
|
110
112
|
|
|
111
|
-
async swap(
|
|
113
|
+
async swap(
|
|
114
|
+
params: CpmmSwapRequest,
|
|
115
|
+
balances?: Map<string, bigint>,
|
|
116
|
+
): Promise<ExecuteScriptResult> {
|
|
112
117
|
if (!this.scope.signer) {
|
|
113
118
|
throw new Error('Signer is required for swap operation');
|
|
114
119
|
}
|
|
115
120
|
|
|
116
|
-
const poolState = await this.getPoolState(params.
|
|
121
|
+
const poolState = await this.getPoolState(params.tokenInId, params.tokenOutId);
|
|
117
122
|
const swapDetails = CpmmModule.computeSwapAmount({
|
|
118
123
|
state: poolState,
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
tokenInId: params.tokenInId,
|
|
125
|
+
tokenOutId: params.tokenOutId,
|
|
121
126
|
amountIn: params.amountIn,
|
|
122
127
|
amountOut: params.amountOut,
|
|
123
|
-
|
|
128
|
+
slippageBps: params.slippageBps,
|
|
124
129
|
});
|
|
125
130
|
|
|
126
131
|
if (swapDetails.priceImpact >= MAX_PRICE_IMPACT) {
|
|
@@ -133,13 +138,13 @@ export class CpmmModule extends ModuleBase {
|
|
|
133
138
|
throw new InsufficientBalanceError(
|
|
134
139
|
swapDetails.tokenInInfo.symbol,
|
|
135
140
|
prettifyTokenAmount(swapDetails.tokenInAmount, swapDetails.tokenInInfo.decimals) ??
|
|
136
|
-
|
|
141
|
+
`${swapDetails.tokenInAmount}`,
|
|
137
142
|
prettifyTokenAmount(available, swapDetails.tokenInInfo.decimals) ?? `${available}`,
|
|
138
143
|
);
|
|
139
144
|
}
|
|
140
145
|
}
|
|
141
146
|
|
|
142
|
-
const
|
|
147
|
+
const ttlMinutes = params.ttlMinutes ?? 60;
|
|
143
148
|
|
|
144
149
|
if (swapDetails.swapType === 'ExactIn') {
|
|
145
150
|
let attoAlphAmount = this.getExtraAlphAmount(
|
|
@@ -164,7 +169,7 @@ export class CpmmModule extends ModuleBase {
|
|
|
164
169
|
tokenInId: swapDetails.tokenInInfo.id,
|
|
165
170
|
amountIn: swapDetails.tokenInAmount,
|
|
166
171
|
amountOutMin: swapDetails.minimalTokenOutAmount!,
|
|
167
|
-
deadline: deadline(
|
|
172
|
+
deadline: deadline(ttlMinutes),
|
|
168
173
|
},
|
|
169
174
|
attoAlphAmount,
|
|
170
175
|
tokens,
|
|
@@ -192,7 +197,7 @@ export class CpmmModule extends ModuleBase {
|
|
|
192
197
|
tokenInId: swapDetails.tokenInInfo.id,
|
|
193
198
|
amountInMax: swapDetails.maximalTokenInAmount!,
|
|
194
199
|
amountOut: swapDetails.tokenOutAmount,
|
|
195
|
-
deadline: deadline(
|
|
200
|
+
deadline: deadline(ttlMinutes),
|
|
196
201
|
},
|
|
197
202
|
attoAlphAmount,
|
|
198
203
|
tokens,
|
|
@@ -202,62 +207,73 @@ export class CpmmModule extends ModuleBase {
|
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
async addLiquidity(
|
|
205
|
-
params:
|
|
210
|
+
params: CpmmAddLiquidityRequest,
|
|
206
211
|
balances?: Map<string, bigint>,
|
|
207
212
|
): Promise<ExecuteScriptResult> {
|
|
208
213
|
if (!this.scope.signer) {
|
|
209
214
|
throw new Error('Signer is required for addLiquidity operation');
|
|
210
215
|
}
|
|
211
216
|
|
|
212
|
-
const {
|
|
217
|
+
const {
|
|
218
|
+
poolState,
|
|
219
|
+
tokenAId,
|
|
220
|
+
tokenBId,
|
|
221
|
+
amountA,
|
|
222
|
+
amountB,
|
|
223
|
+
slippageBps,
|
|
224
|
+
sender,
|
|
225
|
+
ttlMinutes = 60,
|
|
226
|
+
} = params;
|
|
227
|
+
const tokenAInfo = CpmmModule.getTokenInfoFromPoolState(poolState, tokenAId, 'tokenAId');
|
|
228
|
+
const tokenBInfo = CpmmModule.getTokenInfoFromPoolState(poolState, tokenBId, 'tokenBId');
|
|
213
229
|
|
|
214
230
|
if (amountA === 0n || amountB === 0n) {
|
|
215
231
|
throw new Error('The input amount must be greater than 0');
|
|
216
232
|
}
|
|
217
233
|
|
|
218
234
|
if (balances) {
|
|
219
|
-
const tokenAAvailable = balances.get(
|
|
235
|
+
const tokenAAvailable = balances.get(tokenAInfo.id) ?? 0n;
|
|
220
236
|
if (tokenAAvailable < amountA) {
|
|
221
237
|
throw new InsufficientBalanceError(
|
|
222
|
-
|
|
223
|
-
prettifyTokenAmount(amountA,
|
|
224
|
-
prettifyTokenAmount(tokenAAvailable,
|
|
238
|
+
tokenAInfo.symbol,
|
|
239
|
+
prettifyTokenAmount(amountA, tokenAInfo.decimals) ?? `${amountA}`,
|
|
240
|
+
prettifyTokenAmount(tokenAAvailable, tokenAInfo.decimals) ?? `${tokenAAvailable}`,
|
|
225
241
|
);
|
|
226
242
|
}
|
|
227
243
|
|
|
228
|
-
const tokenBAvailable = balances.get(
|
|
244
|
+
const tokenBAvailable = balances.get(tokenBInfo.id) ?? 0n;
|
|
229
245
|
if (tokenBAvailable < amountB) {
|
|
230
246
|
throw new InsufficientBalanceError(
|
|
231
|
-
|
|
232
|
-
prettifyTokenAmount(amountB,
|
|
233
|
-
prettifyTokenAmount(tokenBAvailable,
|
|
247
|
+
tokenBInfo.symbol,
|
|
248
|
+
prettifyTokenAmount(amountB, tokenBInfo.decimals) ?? `${amountB}`,
|
|
249
|
+
prettifyTokenAmount(tokenBAvailable, tokenBInfo.decimals) ?? `${tokenBAvailable}`,
|
|
234
250
|
);
|
|
235
251
|
}
|
|
236
252
|
}
|
|
237
253
|
|
|
238
|
-
const isInitial =
|
|
239
|
-
const amountAMin = isInitial ? amountA : CpmmModule.minimalAmount(amountA,
|
|
240
|
-
const amountBMin = isInitial ? amountB : CpmmModule.minimalAmount(amountB,
|
|
254
|
+
const isInitial = poolState.reserve0 === 0n && poolState.reserve1 === 0n;
|
|
255
|
+
const amountAMin = isInitial ? amountA : CpmmModule.minimalAmount(amountA, slippageBps);
|
|
256
|
+
const amountBMin = isInitial ? amountB : CpmmModule.minimalAmount(amountB, slippageBps);
|
|
241
257
|
|
|
242
258
|
const [amount0Desired, amount1Desired, amount0Min, amount1Min] =
|
|
243
|
-
|
|
259
|
+
tokenAId === poolState.token0Info.id
|
|
244
260
|
? [amountA, amountB, amountAMin, amountBMin]
|
|
245
261
|
: [amountB, amountA, amountBMin, amountAMin];
|
|
246
262
|
|
|
247
263
|
// Calculate ALPH amounts properly
|
|
248
|
-
const extraAlph = this.getExtraAlphAmount(
|
|
264
|
+
const extraAlph = this.getExtraAlphAmount(tokenAId, tokenBId);
|
|
249
265
|
let attoAlphAmount = extraAlph + DUST_AMOUNT;
|
|
250
266
|
const tokens: Array<{ id: string; amount: bigint }> = [];
|
|
251
267
|
|
|
252
268
|
// Handle ALPH token properly - don't double count it
|
|
253
|
-
if (
|
|
269
|
+
if (tokenAId === ALPH_TOKEN_ID) {
|
|
254
270
|
attoAlphAmount += amountA;
|
|
255
|
-
tokens.push({ id:
|
|
256
|
-
} else if (
|
|
271
|
+
tokens.push({ id: tokenBId, amount: amountB });
|
|
272
|
+
} else if (tokenBId === ALPH_TOKEN_ID) {
|
|
257
273
|
attoAlphAmount += amountB;
|
|
258
|
-
tokens.push({ id:
|
|
274
|
+
tokens.push({ id: tokenAId, amount: amountA });
|
|
259
275
|
} else {
|
|
260
|
-
tokens.push({ id:
|
|
276
|
+
tokens.push({ id: tokenAId, amount: amountA }, { id: tokenBId, amount: amountB });
|
|
261
277
|
}
|
|
262
278
|
|
|
263
279
|
const result = await AddLiquidity.execute({
|
|
@@ -265,12 +281,12 @@ export class CpmmModule extends ModuleBase {
|
|
|
265
281
|
initialFields: {
|
|
266
282
|
sender,
|
|
267
283
|
router: this.config.routerId,
|
|
268
|
-
pair:
|
|
284
|
+
pair: poolState.poolId,
|
|
269
285
|
amount0Desired,
|
|
270
286
|
amount1Desired,
|
|
271
287
|
amount0Min,
|
|
272
288
|
amount1Min,
|
|
273
|
-
deadline: deadline(
|
|
289
|
+
deadline: deadline(ttlMinutes),
|
|
274
290
|
},
|
|
275
291
|
attoAlphAmount,
|
|
276
292
|
tokens,
|
|
@@ -278,32 +294,39 @@ export class CpmmModule extends ModuleBase {
|
|
|
278
294
|
return result;
|
|
279
295
|
}
|
|
280
296
|
|
|
281
|
-
async removeLiquidity(params:
|
|
297
|
+
async removeLiquidity(params: CpmmRemoveLiquidityRequest): Promise<ExecuteScriptResult> {
|
|
282
298
|
if (!this.scope.signer) {
|
|
283
299
|
throw new Error('Signer is required for removeLiquidity operation');
|
|
284
300
|
}
|
|
285
301
|
|
|
286
|
-
const {
|
|
287
|
-
|
|
288
|
-
|
|
302
|
+
const {
|
|
303
|
+
poolState,
|
|
304
|
+
liquidity,
|
|
305
|
+
totalLiquidityAmount,
|
|
306
|
+
slippageBps,
|
|
307
|
+
sender,
|
|
308
|
+
ttlMinutes = 60,
|
|
309
|
+
} = params;
|
|
310
|
+
const ownedLiquidity = totalLiquidityAmount ?? poolState.totalSupply;
|
|
311
|
+
const details = CpmmModule.computeRemoveLiquidityAmounts(poolState, ownedLiquidity, liquidity);
|
|
289
312
|
|
|
290
|
-
const amount0Min = CpmmModule.minimalAmount(details.amount0,
|
|
291
|
-
const amount1Min = CpmmModule.minimalAmount(details.amount1,
|
|
313
|
+
const amount0Min = CpmmModule.minimalAmount(details.amount0, slippageBps);
|
|
314
|
+
const amount1Min = CpmmModule.minimalAmount(details.amount1, slippageBps);
|
|
292
315
|
|
|
293
316
|
const result = await RemoveLiquidity.execute({
|
|
294
317
|
signer: this.scope.signer,
|
|
295
318
|
initialFields: {
|
|
296
319
|
sender,
|
|
297
320
|
router: this.config.routerId,
|
|
298
|
-
pairId:
|
|
321
|
+
pairId: poolState.poolId,
|
|
299
322
|
liquidity,
|
|
300
323
|
amount0Min,
|
|
301
324
|
amount1Min,
|
|
302
|
-
deadline: deadline(
|
|
325
|
+
deadline: deadline(ttlMinutes),
|
|
303
326
|
},
|
|
304
327
|
attoAlphAmount:
|
|
305
|
-
this.getExtraAlphAmount(
|
|
306
|
-
tokens: [{ id:
|
|
328
|
+
this.getExtraAlphAmount(poolState.token0Info.id, poolState.token1Info.id) + DUST_AMOUNT,
|
|
329
|
+
tokens: [{ id: poolState.poolId, amount: liquidity }],
|
|
307
330
|
});
|
|
308
331
|
return result;
|
|
309
332
|
}
|
|
@@ -312,7 +335,7 @@ export class CpmmModule extends ModuleBase {
|
|
|
312
335
|
tokenAId: string,
|
|
313
336
|
tokenBId: string,
|
|
314
337
|
liquidityBalance: bigint,
|
|
315
|
-
): Promise<
|
|
338
|
+
): Promise<CpmmClaimableAmounts> {
|
|
316
339
|
const state = await this.getPoolState(tokenAId, tokenBId);
|
|
317
340
|
const details = CpmmModule.computeClaimableAmounts(state, liquidityBalance);
|
|
318
341
|
return {
|
|
@@ -323,18 +346,23 @@ export class CpmmModule extends ModuleBase {
|
|
|
323
346
|
};
|
|
324
347
|
}
|
|
325
348
|
|
|
326
|
-
async createPool(
|
|
349
|
+
async createPool(
|
|
350
|
+
params: CpmmCreatePoolRequest,
|
|
351
|
+
): Promise<ExecuteScriptResult & { poolId: string }> {
|
|
327
352
|
if (!this.scope.signer) {
|
|
328
353
|
throw new Error('Signer is required for createPool operation');
|
|
329
354
|
}
|
|
330
355
|
|
|
331
|
-
const {
|
|
332
|
-
const poolId = this.getPoolId(
|
|
356
|
+
const { tokenAId, tokenBId, sender, initialLiquidity } = params;
|
|
357
|
+
const poolId = this.getPoolId(tokenAId, tokenBId);
|
|
333
358
|
|
|
334
|
-
if (
|
|
335
|
-
const
|
|
359
|
+
if (initialLiquidity) {
|
|
360
|
+
const { tokenAAmount, tokenBAmount } = initialLiquidity;
|
|
361
|
+
const [token0Id, token1Id] = sortTokens(tokenAId, tokenBId);
|
|
336
362
|
const [amount0, amount1] =
|
|
337
|
-
token0Id ===
|
|
363
|
+
token0Id === tokenAId ? [tokenAAmount, tokenBAmount] : [tokenBAmount, tokenAAmount];
|
|
364
|
+
const state = await TokenPairFactory.at(addressFromContractId(this.config.factoryId)).fetchState();
|
|
365
|
+
|
|
338
366
|
const result = await CreatePairAndAddLiquidity.execute({
|
|
339
367
|
signer: this.scope.signer,
|
|
340
368
|
initialFields: {
|
|
@@ -345,8 +373,9 @@ export class CpmmModule extends ModuleBase {
|
|
|
345
373
|
token1Id,
|
|
346
374
|
amount0,
|
|
347
375
|
amount1,
|
|
376
|
+
dexAccount: state.fields.dexAccount0
|
|
348
377
|
},
|
|
349
|
-
attoAlphAmount: ONE_ALPH + this.getExtraAlphAmount(
|
|
378
|
+
attoAlphAmount: ONE_ALPH + this.getExtraAlphAmount(tokenAId, tokenBId),
|
|
350
379
|
tokens: [
|
|
351
380
|
{ id: token0Id, amount: amount0 },
|
|
352
381
|
{ id: token1Id, amount: amount1 },
|
|
@@ -361,13 +390,13 @@ export class CpmmModule extends ModuleBase {
|
|
|
361
390
|
payer: sender,
|
|
362
391
|
factory: this.config.factoryId,
|
|
363
392
|
alphAmount: ONE_ALPH,
|
|
364
|
-
tokenAId
|
|
365
|
-
tokenBId
|
|
393
|
+
tokenAId,
|
|
394
|
+
tokenBId,
|
|
366
395
|
},
|
|
367
|
-
attoAlphAmount: ONE_ALPH + this.getExtraAlphAmount(
|
|
396
|
+
attoAlphAmount: ONE_ALPH + this.getExtraAlphAmount(tokenAId, tokenBId),
|
|
368
397
|
tokens: [
|
|
369
|
-
{ id:
|
|
370
|
-
{ id:
|
|
398
|
+
{ id: tokenAId, amount: 1n },
|
|
399
|
+
{ id: tokenBId, amount: 1n },
|
|
371
400
|
],
|
|
372
401
|
});
|
|
373
402
|
return { ...result, poolId };
|
|
@@ -387,8 +416,10 @@ export class CpmmModule extends ModuleBase {
|
|
|
387
416
|
}
|
|
388
417
|
}
|
|
389
418
|
|
|
390
|
-
static computeSwapAmount(params:
|
|
391
|
-
const { state,
|
|
419
|
+
static computeSwapAmount(params: CpmmSwapQuoteParams): CpmmSwapQuote {
|
|
420
|
+
const { state, tokenInId, tokenOutId, amountIn, amountOut, slippageBps } = params;
|
|
421
|
+
const tokenInInfo = this.getTokenInfoFromPoolState(state, tokenInId, 'tokenInId');
|
|
422
|
+
const tokenOutInfo = this.getTokenInfoFromPoolState(state, tokenOutId, 'tokenOutId');
|
|
392
423
|
|
|
393
424
|
let swapType: 'ExactIn' | 'ExactOut';
|
|
394
425
|
let tokenInAmount: bigint;
|
|
@@ -397,10 +428,10 @@ export class CpmmModule extends ModuleBase {
|
|
|
397
428
|
if (amountIn !== undefined) {
|
|
398
429
|
swapType = 'ExactIn';
|
|
399
430
|
tokenInAmount = amountIn;
|
|
400
|
-
tokenOutAmount = CpmmModule.getAmountOut(state,
|
|
431
|
+
tokenOutAmount = CpmmModule.getAmountOut(state, tokenInInfo.id, amountIn);
|
|
401
432
|
} else if (amountOut !== undefined) {
|
|
402
433
|
swapType = 'ExactOut';
|
|
403
|
-
tokenInAmount = CpmmModule.getAmountIn(state,
|
|
434
|
+
tokenInAmount = CpmmModule.getAmountIn(state, tokenOutInfo.id, amountOut);
|
|
404
435
|
tokenOutAmount = amountOut;
|
|
405
436
|
} else {
|
|
406
437
|
throw new Error('Either amountIn or amountOut must be specified');
|
|
@@ -409,7 +440,7 @@ export class CpmmModule extends ModuleBase {
|
|
|
409
440
|
const priceImpact = this.calcPriceImpact(
|
|
410
441
|
state.reserve0,
|
|
411
442
|
state.reserve1,
|
|
412
|
-
|
|
443
|
+
tokenInInfo.id,
|
|
413
444
|
state.token0Info.id,
|
|
414
445
|
tokenInAmount,
|
|
415
446
|
tokenOutAmount,
|
|
@@ -418,45 +449,47 @@ export class CpmmModule extends ModuleBase {
|
|
|
418
449
|
return {
|
|
419
450
|
swapType,
|
|
420
451
|
state,
|
|
421
|
-
tokenInInfo
|
|
422
|
-
tokenOutInfo
|
|
452
|
+
tokenInInfo,
|
|
453
|
+
tokenOutInfo,
|
|
423
454
|
tokenInAmount,
|
|
424
455
|
tokenOutAmount,
|
|
425
456
|
priceImpact,
|
|
426
457
|
minimalTokenOutAmount:
|
|
427
|
-
swapType === 'ExactIn' ? this.minimalAmount(tokenOutAmount,
|
|
458
|
+
swapType === 'ExactIn' ? this.minimalAmount(tokenOutAmount, slippageBps) : undefined,
|
|
428
459
|
maximalTokenInAmount:
|
|
429
|
-
swapType === 'ExactOut' ? this.maximalAmount(tokenInAmount,
|
|
460
|
+
swapType === 'ExactOut' ? this.maximalAmount(tokenInAmount, slippageBps) : undefined,
|
|
430
461
|
};
|
|
431
462
|
}
|
|
432
463
|
|
|
433
|
-
static computeLiquidityAmounts(
|
|
434
|
-
|
|
464
|
+
static computeLiquidityAmounts(
|
|
465
|
+
params: CpmmAddLiquidityQuoteParams,
|
|
466
|
+
): CpmmAddLiquidityQuote {
|
|
467
|
+
const { poolState, tokenAId, tokenBId, amountA, amountB, inputType = 'TokenA' } = params;
|
|
435
468
|
|
|
436
|
-
if (!
|
|
469
|
+
if (!poolState) {
|
|
437
470
|
// Initial liquidity
|
|
438
|
-
if (
|
|
471
|
+
if (amountA === undefined || amountB === undefined) {
|
|
439
472
|
throw new Error('Both amountA and amountB are required for initial liquidity');
|
|
440
473
|
}
|
|
441
|
-
return this.getInitLiquidityDetails(
|
|
474
|
+
return this.getInitLiquidityDetails(tokenAId, tokenBId, amountA, amountB);
|
|
442
475
|
}
|
|
443
476
|
|
|
444
477
|
// Adding to existing pool
|
|
445
|
-
const inputTokenId = inputType === 'TokenA' ?
|
|
478
|
+
const inputTokenId = inputType === 'TokenA' ? tokenAId : tokenBId;
|
|
446
479
|
const inputAmount = inputType === 'TokenA' ? amountA : amountB;
|
|
447
480
|
|
|
448
|
-
if (
|
|
481
|
+
if (inputAmount === undefined) {
|
|
449
482
|
throw new Error(`Amount for ${inputType} is required`);
|
|
450
483
|
}
|
|
451
484
|
|
|
452
|
-
return this.getLiquidityDetails(
|
|
485
|
+
return this.getLiquidityDetails(poolState, inputTokenId, inputAmount, inputType);
|
|
453
486
|
}
|
|
454
487
|
|
|
455
488
|
static computeRemoveLiquidityAmounts(
|
|
456
489
|
state: CpmmPoolContractState,
|
|
457
490
|
totalLiquidity: bigint,
|
|
458
491
|
liquidityToRemove: bigint,
|
|
459
|
-
):
|
|
492
|
+
): CpmmRemoveLiquidityQuote {
|
|
460
493
|
if (liquidityToRemove > totalLiquidity) {
|
|
461
494
|
throw new Error('Liquidity exceeds total liquidity amount');
|
|
462
495
|
}
|
|
@@ -483,7 +516,7 @@ export class CpmmModule extends ModuleBase {
|
|
|
483
516
|
static computeClaimableAmounts(
|
|
484
517
|
state: CpmmPoolContractState,
|
|
485
518
|
liquidityBalance: bigint,
|
|
486
|
-
):
|
|
519
|
+
): CpmmRemoveLiquidityQuote {
|
|
487
520
|
return this.computeRemoveLiquidityAmounts(state, liquidityBalance, liquidityBalance);
|
|
488
521
|
}
|
|
489
522
|
|
|
@@ -527,15 +560,7 @@ export class CpmmModule extends ModuleBase {
|
|
|
527
560
|
inputTokenId: string,
|
|
528
561
|
inputAmount: bigint,
|
|
529
562
|
inputType: 'TokenA' | 'TokenB', // First or second token in the token input box
|
|
530
|
-
): {
|
|
531
|
-
state: CpmmPoolContractState;
|
|
532
|
-
tokenAId: string;
|
|
533
|
-
tokenBId: string;
|
|
534
|
-
amountA: bigint;
|
|
535
|
-
amountB: bigint;
|
|
536
|
-
shareAmount: bigint;
|
|
537
|
-
sharePercentage: number;
|
|
538
|
-
} {
|
|
563
|
+
): CpmmAddLiquidityQuote {
|
|
539
564
|
const isInputToken0 = inputTokenId === state.token0Info.id;
|
|
540
565
|
const [reserveA, reserveB] = isInputToken0
|
|
541
566
|
? [state.reserve0, state.reserve1]
|
|
@@ -588,14 +613,7 @@ export class CpmmModule extends ModuleBase {
|
|
|
588
613
|
tokenBId: string,
|
|
589
614
|
amountA: bigint,
|
|
590
615
|
amountB: bigint,
|
|
591
|
-
): {
|
|
592
|
-
tokenAId: string;
|
|
593
|
-
tokenBId: string;
|
|
594
|
-
amountA: bigint;
|
|
595
|
-
amountB: bigint;
|
|
596
|
-
shareAmount: bigint;
|
|
597
|
-
sharePercentage: number;
|
|
598
|
-
} {
|
|
616
|
+
): CpmmAddLiquidityQuote {
|
|
599
617
|
const liquidity = MathUtil.sqrt(amountA * amountB);
|
|
600
618
|
if (liquidity <= MINIMUM_LIQUIDITY) {
|
|
601
619
|
throw new InsufficientLiquidityError('Insufficient initial liquidity');
|
|
@@ -610,6 +628,20 @@ export class CpmmModule extends ModuleBase {
|
|
|
610
628
|
};
|
|
611
629
|
}
|
|
612
630
|
|
|
631
|
+
private static getTokenInfoFromPoolState(
|
|
632
|
+
state: CpmmPoolContractState,
|
|
633
|
+
tokenId: string,
|
|
634
|
+
tokenLabel: string,
|
|
635
|
+
): TokenInfo {
|
|
636
|
+
if (state.token0Info.id === tokenId) {
|
|
637
|
+
return state.token0Info;
|
|
638
|
+
}
|
|
639
|
+
if (state.token1Info.id === tokenId) {
|
|
640
|
+
return state.token1Info;
|
|
641
|
+
}
|
|
642
|
+
throw new Error(`Unknown ${tokenLabel} ${tokenId} for pool ${state.poolId}`);
|
|
643
|
+
}
|
|
644
|
+
|
|
613
645
|
private static _getAmountOut(amountIn: bigint, reserveIn: bigint, reserveOut: bigint): bigint {
|
|
614
646
|
const amountInExcludeFee = 997n * amountIn;
|
|
615
647
|
const numerator = amountInExcludeFee * reserveOut;
|
package/src/cpmm/types.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { TokenInfo } from '@alephium/token-list';
|
|
2
2
|
|
|
3
|
+
export type CpmmTokenId = string;
|
|
4
|
+
export type CpmmSlippageBps = bigint;
|
|
5
|
+
export type CpmmInputType = 'TokenA' | 'TokenB';
|
|
6
|
+
|
|
3
7
|
export interface CpmmConfig {
|
|
4
8
|
groupIndex: number;
|
|
5
9
|
factoryId: string;
|
|
@@ -17,17 +21,26 @@ export interface CpmmPoolContractState {
|
|
|
17
21
|
dexAccount: string;
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
export interface
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
export interface CpmmSwapRequest {
|
|
25
|
+
tokenInId: CpmmTokenId;
|
|
26
|
+
tokenOutId: CpmmTokenId;
|
|
23
27
|
amountIn?: bigint;
|
|
24
28
|
amountOut?: bigint;
|
|
25
|
-
|
|
29
|
+
slippageBps: CpmmSlippageBps;
|
|
26
30
|
sender: string;
|
|
27
|
-
|
|
31
|
+
ttlMinutes?: number; // defaults to 60
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CpmmSwapQuoteParams {
|
|
35
|
+
state: CpmmPoolContractState;
|
|
36
|
+
tokenInId: CpmmTokenId;
|
|
37
|
+
tokenOutId: CpmmTokenId;
|
|
38
|
+
amountIn?: bigint;
|
|
39
|
+
amountOut?: bigint;
|
|
40
|
+
slippageBps: CpmmSlippageBps;
|
|
28
41
|
}
|
|
29
42
|
|
|
30
|
-
export interface
|
|
43
|
+
export interface CpmmSwapQuote {
|
|
31
44
|
swapType: 'ExactIn' | 'ExactOut';
|
|
32
45
|
state: CpmmPoolContractState;
|
|
33
46
|
tokenInInfo: TokenInfo;
|
|
@@ -39,18 +52,27 @@ export interface SwapDetails {
|
|
|
39
52
|
priceImpact: number;
|
|
40
53
|
}
|
|
41
54
|
|
|
42
|
-
export interface
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
export interface CpmmAddLiquidityRequest {
|
|
56
|
+
poolState: CpmmPoolContractState;
|
|
57
|
+
tokenAId: CpmmTokenId;
|
|
58
|
+
tokenBId: CpmmTokenId;
|
|
46
59
|
amountA: bigint;
|
|
47
60
|
amountB: bigint;
|
|
48
|
-
|
|
61
|
+
slippageBps: CpmmSlippageBps;
|
|
49
62
|
sender: string;
|
|
50
|
-
|
|
63
|
+
ttlMinutes?: number; // defaults to 60
|
|
51
64
|
}
|
|
52
65
|
|
|
53
|
-
export interface
|
|
66
|
+
export interface CpmmAddLiquidityQuoteParams {
|
|
67
|
+
poolState?: CpmmPoolContractState;
|
|
68
|
+
tokenAId: CpmmTokenId;
|
|
69
|
+
tokenBId: CpmmTokenId;
|
|
70
|
+
amountA?: bigint;
|
|
71
|
+
amountB?: bigint;
|
|
72
|
+
inputType?: CpmmInputType;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface CpmmAddLiquidityQuote {
|
|
54
76
|
state?: CpmmPoolContractState;
|
|
55
77
|
tokenAId: string;
|
|
56
78
|
tokenBId: string;
|
|
@@ -60,16 +82,16 @@ export interface AddLiquidityDetails {
|
|
|
60
82
|
sharePercentage: number;
|
|
61
83
|
}
|
|
62
84
|
|
|
63
|
-
export interface
|
|
64
|
-
|
|
85
|
+
export interface CpmmRemoveLiquidityRequest {
|
|
86
|
+
poolState: CpmmPoolContractState;
|
|
65
87
|
liquidity: bigint;
|
|
66
88
|
totalLiquidityAmount?: bigint;
|
|
67
|
-
|
|
89
|
+
slippageBps: CpmmSlippageBps;
|
|
68
90
|
sender: string;
|
|
69
|
-
|
|
91
|
+
ttlMinutes?: number; // defaults to 60
|
|
70
92
|
}
|
|
71
93
|
|
|
72
|
-
export interface
|
|
94
|
+
export interface CpmmRemoveLiquidityQuote {
|
|
73
95
|
state: CpmmPoolContractState;
|
|
74
96
|
token0: TokenInfo;
|
|
75
97
|
amount0: bigint;
|
|
@@ -79,35 +101,19 @@ export interface RemoveLiquidityDetails {
|
|
|
79
101
|
remainSharePercentage: number;
|
|
80
102
|
}
|
|
81
103
|
|
|
82
|
-
export interface
|
|
104
|
+
export interface CpmmClaimableAmounts {
|
|
83
105
|
token0: TokenInfo;
|
|
84
106
|
amount0: bigint;
|
|
85
107
|
token1: TokenInfo;
|
|
86
108
|
amount1: bigint;
|
|
87
109
|
}
|
|
88
110
|
|
|
89
|
-
export interface
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
export interface CpmmCreatePoolRequest {
|
|
112
|
+
tokenAId: CpmmTokenId;
|
|
113
|
+
tokenBId: CpmmTokenId;
|
|
92
114
|
sender: string;
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
export interface ComputeSwapParams {
|
|
98
|
-
state: CpmmPoolContractState;
|
|
99
|
-
tokenIn: TokenInfo;
|
|
100
|
-
tokenOut: TokenInfo;
|
|
101
|
-
amountIn?: bigint;
|
|
102
|
-
amountOut?: bigint;
|
|
103
|
-
slippage: bigint; // bps
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface ComputeLiquidityParams {
|
|
107
|
-
state?: CpmmPoolContractState;
|
|
108
|
-
tokenA: TokenInfo;
|
|
109
|
-
tokenB: TokenInfo;
|
|
110
|
-
amountA?: bigint;
|
|
111
|
-
amountB?: bigint;
|
|
112
|
-
inputType?: 'TokenA' | 'TokenB';
|
|
115
|
+
initialLiquidity?: {
|
|
116
|
+
tokenAAmount: bigint;
|
|
117
|
+
tokenBAmount: bigint;
|
|
118
|
+
};
|
|
113
119
|
}
|
package/src/index.ts
CHANGED
package/src/moduleBase.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Logger } from './common/logger';
|
|
2
2
|
import { createLogger } from './common/logger';
|
|
3
|
-
import type {
|
|
3
|
+
import type { Powfi } from './powfi';
|
|
4
4
|
|
|
5
5
|
export interface ModuleBaseProps {
|
|
6
|
-
scope:
|
|
6
|
+
scope: Powfi;
|
|
7
7
|
moduleName: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -28,7 +28,7 @@ const joinMsg = (...args: unknown[]): string =>
|
|
|
28
28
|
.join(', ');
|
|
29
29
|
|
|
30
30
|
export default class ModuleBase {
|
|
31
|
-
public scope:
|
|
31
|
+
public scope: Powfi;
|
|
32
32
|
private disabled = false;
|
|
33
33
|
protected logger: Logger;
|
|
34
34
|
|