UNPKG

@indigo-labs/indigo-sdk

Version:

Indigo SDK for interacting with Indigo endpoints via lucid-evolution

1,759 lines (1,507 loc) 119 kB
import { assert, beforeEach, test } from 'vitest'; import { IndigoTestContext, repeat, runAndAwaitTx, runAndAwaitTxBuilder, } from '../test-helpers'; import { createIndigoTestContext, EXAMPLE_TOKEN_1, } from '../indigo-test-helpers'; import { benchmarkAndAwaitTx } from '../utils/benchmark-utils'; import { batchProcessStableswapOrders, cancelStableswapOrder, createStableswapOrder, updateStableswapPoolFees, } from '../../src/contracts/stableswap/transactions'; import { createScriptAddress, fromSystemParamsAsset, mkTreasuryAddr, } from '../../src'; import { addAssets, Assets, credentialToAddress, fromHex, fromText, paymentCredentialOf, UTxO, } from '@lucid-evolution/lucid'; import { findAllNecessaryOrefs, findPriceOracleFromCollateralAsset, findStableswapPool, } from '../cdp/cdp-queries'; import { findSingleStableswapOrder, findStableswapOrders, } from './stableswap-queries'; import { feedPriceOracleTx } from '../../src/contracts/price-oracle/transactions'; import { addressFromBech32, assetClassValueOf, lovelacesAmt, mkLovelacesOf, negateAssets, } from '@3rd-eye-labs/cardano-offchain-common'; import { runCreateStableswapPool } from './stableswap-actions'; import { getValueChangeAtAddressAfterAction } from '../utils'; import { array as A } from 'fp-ts'; import { runOpenCdp } from '../cdp/actions'; import { Data } from '@evolution-sdk/evolution'; import { serialiseStableswapOrderDatum } from '../../src/contracts/stableswap/types-new'; import { BASE_MAX_EXECUTION_FEE } from '../../src/contracts/stableswap/helpers'; import { StableswapPoolContent } from '../../src/contracts/cdp/types-new'; import { mutatedBatchProcessStableswapOrders } from './transactions-mutated'; import { expectScriptFailure } from '../utils/asserts'; import { findRandomTreasuryUtxoWithOnlyAda, findRandomTreasuryUtxoWithAsset, } from '../treasury/treasury-queries'; import { createUtxoAtTreasury } from '../endpoints/treasury'; import { rationalFromInt, rationalZero } from '../../src/types/rational'; beforeEach<IndigoTestContext>(async (context: IndigoTestContext) => { await createIndigoTestContext(context); }); test<IndigoTestContext>('Stableswap - Create Order', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, ); const stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); await benchmarkAndAwaitTx( 'Stableswap - Create Order', await createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), context.lucid, context.emulator, ); }); test<IndigoTestContext>('Stableswap - Cancel Order', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, ); const stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); const stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await benchmarkAndAwaitTx( 'Stableswap - Cancel Order', await cancelStableswapOrder( stableswapOrder.utxo, context.systemParams, context.lucid, ), context.lucid, context.emulator, ); }); test<IndigoTestContext>('Stableswap - Batch a single order to mint', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); const stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => benchmarkAndAwaitTx( 'Stableswap - Batch a single order to mint', await batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), context.lucid, context.emulator, ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; assert( assetClassValueOf(treasuryValChange, iassetAc) == 50_000n, 'Unexpected iAsset value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n, 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 50_000n, 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to mint with no minting fee', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, rationalFromInt(1n), // 0% minting fee. rationalZero, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); const stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => await runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; assert( assetClassValueOf(treasuryValChange, iassetAc) == 0n, 'Unexpected iAsset value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n, 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n, 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to mint with collateral asset in the pool', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); let stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; treasuryUtxo = await findRandomTreasuryUtxoWithAsset( context.lucid, context.systemParams, iassetAc, ); context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => benchmarkAndAwaitTx( 'Stableswap - Batch a single order to mint with collateral in the pool', await batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), context.lucid, context.emulator, ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); const adminValueDiff = addAssets( finalAdminValue, negateAssets(initialAdminValue), ); assert( lovelacesAmt(adminValueDiff) >= 0n && lovelacesAmt(adminValueDiff) < 100_000n, ); assert( assetClassValueOf(treasuryValChange, iassetAc) == 50_000n, 'Unexpected iAsset value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 20_000_000n, 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 50_000n, 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to redeem', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); // Mint iAsset to supply the pool with collateral asset. // It also provides the treasury with a UTxO with iAsset. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); let stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); await runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ); // Redeem part of the collateral asset previously supplied to the pool. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 5_000_000n, false, stableswapPool.datum, context.systemParams, context.lucid, ), ); stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; treasuryUtxo = await findRandomTreasuryUtxoWithAsset( context.lucid, context.systemParams, iassetAc, ); context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => benchmarkAndAwaitTx( 'Stableswap - Batch a single order to redeem', await batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), context.lucid, context.emulator, ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); const adminValueDiff = addAssets( finalAdminValue, negateAssets(initialAdminValue), ); assert( lovelacesAmt(adminValueDiff) >= 0n && lovelacesAmt(adminValueDiff) < 100_000n, ); assert( assetClassValueOf(treasuryValChange, iassetAc) == 25_000n && 0n <= lovelacesAmt(treasuryValChange) && lovelacesAmt(treasuryValChange) <= 9_000n, 'Unexpected value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n - (5_000_000n - 25_000n), 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 50_000n - 5_000_000n && assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n + (5_000_000n - 25_000n), 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to redeem with no redemption fee', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, rationalFromInt(1n), // 0% minting fee. rationalZero, // 0% redemption fee. rationalZero, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); // Mint iAsset to supply the pool with collateral asset. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); let stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); await runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ); // Redeem part of the collateral asset previously supplied to the pool. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 5_000_000n, false, stableswapPool.datum, context.systemParams, context.lucid, ), ); stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; // This will not be used in the transaction, but is passed only as a placeholder. treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); const adminValueDiff = addAssets( finalAdminValue, negateAssets(initialAdminValue), ); // This one will result in a bigger gain for the admin as the tx fee is lower assert(lovelacesAmt(adminValueDiff) >= 0n); assert( assetClassValueOf(treasuryValChange, iassetAc) == 0n, 'Unexpected value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n - 5_000_000n, 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 5_000_000n && assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n + 5_000_000n, 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to redeem emptying the pool', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const orefs = await findAllNecessaryOrefs( context.lucid, context.systemParams, context.assetConfigs[0].iassetTokenNameAscii, context.assetConfigs[0].collateralAssets[0].collateralAsset, ); const priceOracleUtxo = await findPriceOracleFromCollateralAsset( context.lucid, orefs.collateralAsset, ); await runAndAwaitTx( context.lucid, feedPriceOracleTx( context.lucid, priceOracleUtxo!, rationalFromInt(1n), context.assetConfigs[0].collateralAssets[0].oracleParams!, context.emulator.slot, ), ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); // Mint extra iAsset to have enough to empty the pool. await runAndAwaitTx( context.lucid, runOpenCdp( context, context.systemParams, context.assetConfigs[0].iassetTokenNameAscii, context.assetConfigs[0].collateralAssets[0].collateralAsset, 10_000_000n, 5_000_000n, ), ); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); // Mint iAsset to supply the pool with collateral asset // It also provides the treasury with a UTxO with iAsset. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); let stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); await runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ); // Redeem all the assets left in the pool. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, // After taking a 0.5% fee, the effective amount is 10_000_000. 10_050_251n, false, stableswapPool.datum, context.systemParams, context.lucid, ), ); stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; treasuryUtxo = await findRandomTreasuryUtxoWithAsset( context.lucid, context.systemParams, iassetAc, ); context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); const initialAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const finalAdminValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.admin.address)); const adminValueDiff = addAssets( finalAdminValue, negateAssets(initialAdminValue), ); assert( lovelacesAmt(adminValueDiff) >= 0n && lovelacesAmt(adminValueDiff) < 100_000n, ); assert( assetClassValueOf(treasuryValChange, iassetAc) == 50_251n && 0n <= lovelacesAmt(treasuryValChange) && lovelacesAmt(treasuryValChange) <= 9_000n, 'Unexpected value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 0n, 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000n - 50_000n - 10_050_251n && assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n + 10_000_000n, 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to mint assets with smaller scale', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, rationalFromInt(1_000n), ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); const stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; assert( assetClassValueOf(treasuryValChange, iassetAc) == 50n, 'Unexpected iAsset value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n, 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000n - 50n, 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to mint assets with bigger scale', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, { numerator: 1n, denominator: 1_000n }, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); const stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); const treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; assert( assetClassValueOf(treasuryValChange, iassetAc) == 50_000_000n, 'Unexpected iAsset value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n, 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000_000n - 50_000_000n, 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to redeem assets with smaller scale', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, rationalFromInt(1_000n), ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); // Mint iAsset to supply the pool with collateral asset. // It also provides the treasury with a UTxO with iAsset. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); let stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); await runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ); // Redeem part of the collateral asset previously supplied to the pool. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 5_000n, false, stableswapPool.datum, context.systemParams, context.lucid, ), ); stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; treasuryUtxo = await findRandomTreasuryUtxoWithAsset( context.lucid, context.systemParams, iassetAc, ); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); assert( assetClassValueOf(treasuryValChange, iassetAc) == 25n && 0n <= lovelacesAmt(treasuryValChange) && lovelacesAmt(treasuryValChange) <= 9_000n, 'Unexpected value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n - (5_000_000n - 25_000n), 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000n - 50n - 5_000n && assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n + (5_000_000n - 25_000n), 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch a single order to redeem assets with bigger scale', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, { numerator: 1n, denominator: 1_000n }, ); let stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); context.lucid.selectWallet.fromSeed(context.users.user.seedPhrase); const initialUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); // Mint iAsset to supply the pool with collateral asset. // It also provides the treasury with a UTxO with iAsset. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 10_000_000n, true, stableswapPool.datum, context.systemParams, context.lucid, ), ); let stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); await createUtxoAtTreasury( mkLovelacesOf(2_000_000n), context.systemParams, context, ); let treasuryUtxo = await findRandomTreasuryUtxoWithOnlyAda( context.lucid, context.systemParams, ); await runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ); // Redeem part of the collateral asset previously supplied to the pool. await runAndAwaitTx( context.lucid, createStableswapOrder( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, 5_000_000_000n, false, stableswapPool.datum, context.systemParams, context.lucid, ), ); stableswapOrder = await findSingleStableswapOrder( context.lucid, context.systemParams.validatorHashes.stableswapHash, fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const iassetAc = { currencySymbol: fromHex( context.systemParams.stableswapParams.iassetSymbol.unCurrencySymbol, ), tokenName: stableswapOrder.datum.iasset, }; treasuryUtxo = await findRandomTreasuryUtxoWithAsset( context.lucid, context.systemParams, iassetAc, ); const [__, treasuryValChange] = await getValueChangeAtAddressAfterAction( context.lucid, mkTreasuryAddr(context.lucid, context.systemParams), async () => runAndAwaitTx( context.lucid, batchProcessStableswapOrders( [stableswapOrder.utxo], stableswapPool.utxo, treasuryUtxo, context.systemParams, context.lucid, ), ), ); /////////////////////////////////// // Checks after last transaction // /////////////////////////////////// stableswapPool = await findStableswapPool( context.lucid, context.systemParams.validatorHashes.cdpHash, fromSystemParamsAsset(context.systemParams.stableswapParams.cdpToken), fromText(context.assetConfigs[0].iassetTokenNameAscii), EXAMPLE_TOKEN_1, ); const finalUserValue = A.reduce<UTxO, Assets>({}, (acc, utxo) => addAssets(acc, utxo.assets), )(await context.lucid.utxosAt(context.users.user.address)); const userValueDiff = addAssets( finalUserValue, negateAssets(initialUserValue), ); assert( assetClassValueOf(treasuryValChange, iassetAc) == 25_000_000n && 0n <= lovelacesAmt(treasuryValChange) && lovelacesAmt(treasuryValChange) <= 9_000n, 'Unexpected value received by the treasury', ); assert( assetClassValueOf(stableswapPool.utxo.assets, EXAMPLE_TOKEN_1) == 10_000_000n - (5_000_000n - 25_000n), 'Unexpected value held by stableswap pool', ); assert( assetClassValueOf(userValueDiff, iassetAc) == 10_000_000_000n - 50_000_000n - 5_000_000_000n && assetClassValueOf(userValueDiff, EXAMPLE_TOKEN_1) == -10_000_000n + (5_000_000n - 25_000n), 'Unexpected value received by order owner', ); }); test<IndigoTestContext>('Stableswap - Batch multiple orders to mint from same owner, 11', async (context: IndigoTestContext) => { context.lucid.selectWallet.fromSeed(context.users.admin.seedPhrase); await runCreateStableswapPool( context.assetConfigs[0].iassetTokenNameAscii, EXAMPLE_TOKEN_1, context, ); let stableswapPool = await findStableswapPool( context.lucid,