From 84e0b725e6b09ff1d290ea741352ac790aae2291 Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Mon, 21 Apr 2025 18:02:12 +0200 Subject: [PATCH 1/8] chore: add multisell stableSwap test --- test/parallel/market.fee.scenarios.test.ts | 57 +++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index 8a687d21d..d81d2bf0e 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -26,7 +26,7 @@ import { } from "../../utils/tx"; import { feeLockErrors, stringToBN, xykErrors } from "../../utils/utils"; import { ApiPromise } from "@polkadot/api"; -import { BN_ZERO, signTx } from "gasp-sdk"; +import { BN_ONE, BN_ZERO, signTx } from "gasp-sdk"; import { getEventResultFromMangataTx } from "../../utils/txHandler"; import { ExtrinsicResult } from "../../utils/eventListeners"; import { @@ -116,6 +116,24 @@ async function prepareForMultiswapScenario( ); } +async function prepareMultiswapPools( + currencies: [firstCurrency: BN, secondCurrency: BN, thirdCurrency: BN], + poolType: string, +) { + const meta = await getFeeLockMetadata(); + const amount = stringToBN( + JSON.parse(JSON.stringify(meta)).swapValueThreshold.toString(), + ).muln(5); + return await Sudo.batchAsSudoFinalized( + Market.createPool(currencies[0], amount, currencies[1], amount, poolType), + Market.createPool(currencies[1], amount, currencies[2], amount, poolType), + Market.createPool(GASP_ASSET_ID, amount, currencies[0], amount), + Market.createPool(GASP_ASSET_ID, amount, currencies[1], amount), + Market.createPool(GASP_ASSET_ID, amount, currencies[2], amount), + Assets.mintToken(currencies[0], testUser, amount), + ); +} + async function sellTokenAndReceiveSuccess( user: User, currencies: [firstCurrency: BN, secondCurrency: BN], @@ -1085,3 +1103,40 @@ describe("Fee checking scenarios, user has only sold asset and sold amount > use ); }); }); + +describe("MultiSell, user has only sold asset", () => { + test("GIVEN multi operation for stable pools AND sale amount > threshold THEN operation operation succeed", async () => { + [thirdCurrency] = await Assets.setupUserWithCurrencies( + sudo, + [threshold.muln(20), threshold.muln(20)], + sudo, + ); + await prepareMultiswapPools( + [firstCurrency, secondCurrency, thirdCurrency], + "Xyk", + ); + const liqId1 = await rpcGetPoolId(firstCurrency, secondCurrency); + const liqId2 = await rpcGetPoolId(secondCurrency, thirdCurrency); + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); + await updateFeeLockMetadata(sudo, null, null, null, [ + [secondCurrency, true], + ]); + await updateFeeLockMetadata(sudo, null, null, null, [ + [thirdCurrency, true], + ]); + + await signTx( + api, + Market.multiswapAssetSell( + [liqId1, liqId2], + firstCurrency, + threshold.muln(2), + thirdCurrency, + BN_ONE, + ), + testUser.keyRingPair, + ); + }); +}); From f57493382608a3c2d6b957b7176db199f1cdd199 Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Tue, 22 Apr 2025 15:40:23 +0200 Subject: [PATCH 2/8] chore: add singleSwap test --- test/parallel/market.fee.scenarios.test.ts | 88 +++++++++++----------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index d81d2bf0e..9110bfd94 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -22,13 +22,14 @@ import { getBalanceOfPool, getPoolIdFromEvent, getTokensAccountInfo, + getUserAssets, updateFeeLockMetadata, } from "../../utils/tx"; import { feeLockErrors, stringToBN, xykErrors } from "../../utils/utils"; import { ApiPromise } from "@polkadot/api"; -import { BN_ONE, BN_ZERO, signTx } from "gasp-sdk"; +import { BN_ZERO, signTx } from "gasp-sdk"; import { getEventResultFromMangataTx } from "../../utils/txHandler"; -import { ExtrinsicResult } from "../../utils/eventListeners"; +import { ExtrinsicResult, filterEventData } from "../../utils/eventListeners"; import { getFeeLockMetadata, rpcCalculateSellPrice, @@ -116,24 +117,6 @@ async function prepareForMultiswapScenario( ); } -async function prepareMultiswapPools( - currencies: [firstCurrency: BN, secondCurrency: BN, thirdCurrency: BN], - poolType: string, -) { - const meta = await getFeeLockMetadata(); - const amount = stringToBN( - JSON.parse(JSON.stringify(meta)).swapValueThreshold.toString(), - ).muln(5); - return await Sudo.batchAsSudoFinalized( - Market.createPool(currencies[0], amount, currencies[1], amount, poolType), - Market.createPool(currencies[1], amount, currencies[2], amount, poolType), - Market.createPool(GASP_ASSET_ID, amount, currencies[0], amount), - Market.createPool(GASP_ASSET_ID, amount, currencies[1], amount), - Market.createPool(GASP_ASSET_ID, amount, currencies[2], amount), - Assets.mintToken(currencies[0], testUser, amount), - ); -} - async function sellTokenAndReceiveSuccess( user: User, currencies: [firstCurrency: BN, secondCurrency: BN], @@ -1104,39 +1087,56 @@ describe("Fee checking scenarios, user has only sold asset and sold amount > use }); }); -describe("MultiSell, user has only sold asset", () => { - test("GIVEN multi operation for stable pools AND sale amount > threshold THEN operation operation succeed", async () => { - [thirdCurrency] = await Assets.setupUserWithCurrencies( - sudo, - [threshold.muln(20), threshold.muln(20)], - sudo, - ); - await prepareMultiswapPools( - [firstCurrency, secondCurrency, thirdCurrency], - "Xyk", +describe("MultiSell, user has only sold asset and buy GASP", () => { + test("GIVEN sell operation for Xyk pools AND sale amount > threshold THEN operation operation succeed", async () => { + const soldAssetAmount = threshold.muln(2); + await Sudo.batchAsSudoFinalized( + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [true, "Xyk"], + [true, "Xyk"], + [true, "Xyk"], + )), + Assets.mintToken(firstCurrency, testUser, soldAssetAmount.muln(3)), ); - const liqId1 = await rpcGetPoolId(firstCurrency, secondCurrency); - const liqId2 = await rpcGetPoolId(secondCurrency, thirdCurrency); await updateFeeLockMetadata(sudo, null, null, null, [ [firstCurrency, true], ]); + const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); await updateFeeLockMetadata(sudo, null, null, null, [ - [secondCurrency, true], - ]); - await updateFeeLockMetadata(sudo, null, null, null, [ - [thirdCurrency, true], + [firstCurrency, true], ]); - await signTx( + const sellPrice = await rpcCalculateSellPrice( + liqId, + firstCurrency, + soldAssetAmount, + ); + + const userGaspAmountBefore = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency, GASP_ASSET_ID], + ); + + const events = await signTx( api, - Market.multiswapAssetSell( - [liqId1, liqId2], - firstCurrency, - threshold.muln(2), - thirdCurrency, - BN_ONE, - ), + Market.sellAsset(liqId, firstCurrency, GASP_ASSET_ID, soldAssetAmount), testUser.keyRingPair, ); + const filteredEvent = await filterEventData(events, "market.AssetsSwapped"); + + const userGaspAmountAfter = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency, GASP_ASSET_ID], + ); + + expect(userGaspAmountBefore[1].free).bnEqual(BN_ZERO); + expect(userGaspAmountAfter[1].free).bnEqual(sellPrice); + expect( + userGaspAmountBefore[0].free.sub(userGaspAmountAfter[0].free), + ).bnEqual(soldAssetAmount); + expect(stringToBN(filteredEvent[0].swaps[0].amountIn)).bnEqual( + soldAssetAmount.muln(997).divn(1000), + ); }); }); From faaff1aba570b2dbea306a2aab638429507aef91 Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Wed, 23 Apr 2025 15:56:05 +0200 Subject: [PATCH 3/8] chore: add StableSwap for test scenario --- test/parallel/market.fee.scenarios.test.ts | 102 +++++++++++---------- 1 file changed, 54 insertions(+), 48 deletions(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index 9110bfd94..d35b2e8ce 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -1087,56 +1087,62 @@ describe("Fee checking scenarios, user has only sold asset and sold amount > use }); }); -describe("MultiSell, user has only sold asset and buy GASP", () => { - test("GIVEN sell operation for Xyk pools AND sale amount > threshold THEN operation operation succeed", async () => { - const soldAssetAmount = threshold.muln(2); - await Sudo.batchAsSudoFinalized( - ...(await addTestExtrinsic( - [firstCurrency, secondCurrency], - [true, "Xyk"], - [true, "Xyk"], - [true, "Xyk"], - )), - Assets.mintToken(firstCurrency, testUser, soldAssetAmount.muln(3)), - ); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); - const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); - - const sellPrice = await rpcCalculateSellPrice( - liqId, - firstCurrency, - soldAssetAmount, - ); +describe("SingleSell, user has only sold asset and buy GASP", () => { + test.each(["Xyk", "StableSwap"])( + "GIVEN sell operation for %s pools AND sale amount > threshold THEN operation operation succeed", + async (poolType) => { + const soldAssetAmount = threshold.muln(2); + await Sudo.batchAsSudoFinalized( + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [true, poolType], + [true, poolType], + [true, poolType], + )), + Assets.mintToken(firstCurrency, testUser, soldAssetAmount.muln(3)), + ); + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); + const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); + + const sellPrice = await rpcCalculateSellPrice( + liqId, + firstCurrency, + soldAssetAmount, + ); - const userGaspAmountBefore = await getUserAssets( - testUser.keyRingPair.address, - [firstCurrency, GASP_ASSET_ID], - ); + const userGaspAmountBefore = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency, GASP_ASSET_ID], + ); - const events = await signTx( - api, - Market.sellAsset(liqId, firstCurrency, GASP_ASSET_ID, soldAssetAmount), - testUser.keyRingPair, - ); - const filteredEvent = await filterEventData(events, "market.AssetsSwapped"); + const events = await signTx( + api, + Market.sellAsset(liqId, firstCurrency, GASP_ASSET_ID, soldAssetAmount), + testUser.keyRingPair, + ); + const filteredEvent = await filterEventData( + events, + "market.AssetsSwapped", + ); - const userGaspAmountAfter = await getUserAssets( - testUser.keyRingPair.address, - [firstCurrency, GASP_ASSET_ID], - ); + const userGaspAmountAfter = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency, GASP_ASSET_ID], + ); - expect(userGaspAmountBefore[1].free).bnEqual(BN_ZERO); - expect(userGaspAmountAfter[1].free).bnEqual(sellPrice); - expect( - userGaspAmountBefore[0].free.sub(userGaspAmountAfter[0].free), - ).bnEqual(soldAssetAmount); - expect(stringToBN(filteredEvent[0].swaps[0].amountIn)).bnEqual( - soldAssetAmount.muln(997).divn(1000), - ); - }); + expect(userGaspAmountBefore[1].free).bnEqual(BN_ZERO); + expect(userGaspAmountAfter[1].free).bnEqual(sellPrice); + expect( + userGaspAmountBefore[0].free.sub(userGaspAmountAfter[0].free), + ).bnEqual(soldAssetAmount); + expect(stringToBN(filteredEvent[0].swaps[0].amountIn)).bnEqual( + soldAssetAmount.muln(997).divn(1000), + ); + }, + ); }); From dc6bd065fb68b119ff3f0738ffe4228b3f3f692b Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Wed, 23 Apr 2025 17:23:59 +0200 Subject: [PATCH 4/8] chore: add new tests --- test/parallel/market.fee.scenarios.test.ts | 101 +++++++++++++++++++-- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index d35b2e8ce..94cc16c7a 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -1087,9 +1087,9 @@ describe("Fee checking scenarios, user has only sold asset and sold amount > use }); }); -describe("SingleSell, user has only sold asset and buy GASP", () => { +describe("User has only sold asset and buy GASP", () => { test.each(["Xyk", "StableSwap"])( - "GIVEN sell operation for %s pools AND sale amount > threshold THEN operation operation succeed", + "SingleSell - GIVEN sell operation for %s pools AND sale amount > threshold THEN operation operation succeed", async (poolType) => { const soldAssetAmount = threshold.muln(2); await Sudo.batchAsSudoFinalized( @@ -1115,7 +1115,7 @@ describe("SingleSell, user has only sold asset and buy GASP", () => { soldAssetAmount, ); - const userGaspAmountBefore = await getUserAssets( + const userAmountBefore = await getUserAssets( testUser.keyRingPair.address, [firstCurrency, GASP_ASSET_ID], ); @@ -1130,16 +1130,99 @@ describe("SingleSell, user has only sold asset and buy GASP", () => { "market.AssetsSwapped", ); - const userGaspAmountAfter = await getUserAssets( + const userAmountAfter = await getUserAssets( testUser.keyRingPair.address, [firstCurrency, GASP_ASSET_ID], ); - expect(userGaspAmountBefore[1].free).bnEqual(BN_ZERO); - expect(userGaspAmountAfter[1].free).bnEqual(sellPrice); - expect( - userGaspAmountBefore[0].free.sub(userGaspAmountAfter[0].free), - ).bnEqual(soldAssetAmount); + expect(userAmountBefore[1].free).bnEqual(BN_ZERO); + expect(userAmountAfter[1].free).bnEqual(sellPrice); + expect(userAmountBefore[0].free.sub(userAmountAfter[0].free)).bnEqual( + soldAssetAmount, + ); + expect(stringToBN(filteredEvent[0].swaps[0].amountIn)).bnEqual( + soldAssetAmount.muln(997).divn(1000), + ); + }, + ); + + test.each(["Xyk", "StableSwap"])( + "MultiSell - GIVEN sell operation for %s pools AND sale amount > threshold THEN operation operation succeed", + async (poolType) => { + const soldAssetAmount = threshold.muln(2); + const poolAmount = threshold.muln(5); + await Sudo.batchAsSudoFinalized( + Market.createPool( + firstCurrency, + poolAmount, + secondCurrency, + poolAmount, + poolType, + ), + Market.createPool( + secondCurrency, + poolAmount, + GASP_ASSET_ID, + poolAmount, + poolType, + ), + Assets.mintToken(firstCurrency, testUser, poolAmount), + ); + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); + const liqId1 = await rpcGetPoolId(firstCurrency, secondCurrency); + const liqId2 = await rpcGetPoolId(secondCurrency, GASP_ASSET_ID); + + const sellPrice1 = await rpcCalculateSellPrice( + liqId1, + firstCurrency, + soldAssetAmount, + ); + + const sellPrice2 = await rpcCalculateSellPrice( + liqId1, + firstCurrency, + sellPrice1, + ); + + const userAmountBefore = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency, GASP_ASSET_ID], + ); + + const events = await signTx( + api, + Market.sellAsset( + [liqId1, liqId2], + firstCurrency, + GASP_ASSET_ID, + soldAssetAmount, + ), + testUser.keyRingPair, + ); + const filteredEvent = await filterEventData( + events, + "market.AssetsSwapped", + ); + + const userAmountAfter = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency, GASP_ASSET_ID], + ); + + const diff = userAmountAfter[1].free.sub(sellPrice2); + + expect(userAmountBefore[1].free).bnEqual(BN_ZERO); + //we still have a problem with checking value in multiswap, so I decided to check that the values differ by less than 0.5 % + expect(diff).bnGt(BN_ZERO); + expect(diff).bnLt(sellPrice2.muln(5).divn(1000)); + expect(userAmountBefore[0].free.sub(userAmountAfter[0].free)).bnEqual( + soldAssetAmount, + ); expect(stringToBN(filteredEvent[0].swaps[0].amountIn)).bnEqual( soldAssetAmount.muln(997).divn(1000), ); From 58bb999ed56f4d7d58e449ba320e0595ca7a954a Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Thu, 24 Apr 2025 17:22:06 +0200 Subject: [PATCH 5/8] chore: add new tests --- test/parallel/market.fee.scenarios.test.ts | 192 +++++++++++++++------ 1 file changed, 143 insertions(+), 49 deletions(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index 94cc16c7a..b23e713a9 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -362,32 +362,35 @@ describe("SingleSell, user has only sold asset", () => { ); }); - test("GIVEN sale amount < threshold THEN operation fails on client", async () => { - await Sudo.batchAsSudoFinalized( - ...(await addTestExtrinsic( - [firstCurrency, secondCurrency], - [true, "Xyk"], - [true, "Xyk"], - [true, "Xyk"], - )), - Assets.mintToken(firstCurrency, testUser, threshold.muln(2)), - ); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); + test.each(["Xyk", "StableSwap"])( + "GIVEN sale amount for %s pool < threshold THEN operation fails on client", + async (poolType) => { + await Sudo.batchAsSudoFinalized( + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [true, poolType], + [true, poolType], + [true, poolType], + )), + Assets.mintToken(firstCurrency, testUser, threshold.muln(2)), + ); + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); - const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); + const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); - await getSwappingTokenError( - testUser, - [firstCurrency, GASP_ASSET_ID], - liqId, - threshold.divn(2), - feeLockErrors.SwapApprovalFail, - "Sell", - true, - ); - }); + await getSwappingTokenError( + testUser, + [firstCurrency, GASP_ASSET_ID], + liqId, + threshold.divn(2), + feeLockErrors.SwapApprovalFail, + "Sell", + true, + ); + }, + ); test("GIVEN sold asset is not whitelisted AND sale amount > threshold THEN operation fails on client", async () => { await Sudo.batchAsSudoFinalized( @@ -869,10 +872,12 @@ describe("MultiSwap scenarios with slippage error, user has only sold asset", () [threshold.muln(20), threshold.muln(20)], sudo, ); - await updateFeeLockMetadata(sudo, null, null, null, [ [firstCurrency, true], ]); + await updateFeeLockMetadata(sudo, null, null, null, [ + [secondCurrency, true], + ]); }); test("GIVEN sellAsset operation AND sale amount > threshold THEN operation fails on client", async () => { @@ -880,12 +885,6 @@ describe("MultiSwap scenarios with slippage error, user has only sold asset", () [firstCurrency, secondCurrency, thirdCurrency], "Xyk", ); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); - await updateFeeLockMetadata(sudo, null, null, null, [ - [secondCurrency, true], - ]); const liqId = await rpcGetPoolId(thirdCurrency, secondCurrency); @@ -905,12 +904,6 @@ describe("MultiSwap scenarios with slippage error, user has only sold asset", () [firstCurrency, secondCurrency, thirdCurrency], "StableSwap", ); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); - await updateFeeLockMetadata(sudo, null, null, null, [ - [secondCurrency, true], - ]); const liqId = await getPoolIdFromEvent(poolEvent); @@ -932,12 +925,6 @@ describe("MultiSwap scenarios with slippage error, user has only sold asset", () ); const liqId = await rpcGetPoolId(thirdCurrency, secondCurrency); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); - await updateFeeLockMetadata(sudo, null, null, null, [ - [secondCurrency, true], - ]); await getSwappingTokenError( testUser, @@ -957,12 +944,6 @@ describe("MultiSwap scenarios with slippage error, user has only sold asset", () ); const liqId = await getPoolIdFromEvent(poolEvent); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); - await updateFeeLockMetadata(sudo, null, null, null, [ - [secondCurrency, true], - ]); await getSwappingTokenError( testUser, @@ -1228,4 +1209,117 @@ describe("User has only sold asset and buy GASP", () => { ); }, ); + + test.each(["Xyk", "StableSwap"])( + "GIVEN sellAsset operation for Xyk pool AND sale amount > threshold AND buying GASP THEN operation fails on client", + async (poolType) => { + const soldAssetAmount = threshold.muln(2); + const poolAmount = threshold.muln(5); + await Sudo.batchAsSudoFinalized( + Market.createPool( + firstCurrency, + poolAmount, + secondCurrency, + poolAmount, + poolType, + ), + Market.createPool( + secondCurrency, + poolAmount, + GASP_ASSET_ID, + poolAmount, + poolType, + ), + Assets.mintToken(firstCurrency, testUser, poolAmount), + ); + + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); + await updateFeeLockMetadata(sudo, null, null, null, [ + [firstCurrency, true], + ]); + + const liqId1 = await rpcGetPoolId(firstCurrency, secondCurrency); + const liqId2 = await rpcGetPoolId(secondCurrency, GASP_ASSET_ID); + + const userAmountBefore = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency], + ); + + const events = await signTx( + api, + Market.sellAsset( + [liqId1, liqId2], + firstCurrency, + GASP_ASSET_ID, + soldAssetAmount, + soldAssetAmount.muln(1000), + ), + testUser.keyRingPair, + ); + + const userAmountAfter = await getUserAssets( + testUser.keyRingPair.address, + [firstCurrency], + ); + + const eventResponse = getEventResultFromMangataTx(events); + expect(eventResponse.state).toEqual(ExtrinsicResult.ExtrinsicFailed); + expect(eventResponse.data).toEqual(xykErrors.InsufficientOutputAmount); + + expect(userAmountBefore[0].free.sub(userAmountAfter[0].free)).bnEqual( + soldAssetAmount.muln(3).divn(1000), + ); + }, + ); + + test.each(["Xyk", "StableSwap"])( + "GIVEN a singleSell for %s pool WHEN a user is selling a token that is not tokenValueThreshold it fails on pre-validation", + async (poolType) => { + const [thirdCurrency] = await Assets.setupUserWithCurrencies( + sudo, + [threshold.muln(20)], + sudo, + ); + + const soldAssetAmount = threshold.muln(2); + const poolAmount = threshold.muln(5); + + await Sudo.batchAsSudoFinalized( + Market.createPool( + thirdCurrency, + poolAmount, + GASP_ASSET_ID, + poolAmount, + poolType, + ), + Assets.mintToken(thirdCurrency, testUser, poolAmount), + ); + + await updateFeeLockMetadata(sudo, null, null, null, [ + [thirdCurrency, true], + ]); + + const liqId = await rpcGetPoolId(thirdCurrency, GASP_ASSET_ID); + + let error: any; + try { + await signTx( + api, + Market.sellAsset( + liqId, + firstCurrency, + GASP_ASSET_ID, + soldAssetAmount, + ), + testUser.keyRingPair, + ); + } catch (e) { + error = e; + } + expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); + }, + ); }); From 9f5b66b4ed8ac831b5488365d8e519ccc67c1f88 Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Tue, 29 Apr 2025 16:51:34 +0200 Subject: [PATCH 6/8] chore: add changes and a new test --- test/parallel/market.fee.scenarios.test.ts | 43 ++++++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index b23e713a9..20d57dca2 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -1298,11 +1298,48 @@ describe("User has only sold asset and buy GASP", () => { Assets.mintToken(thirdCurrency, testUser, poolAmount), ); + const liqId = await rpcGetPoolId(thirdCurrency, GASP_ASSET_ID); + + let error: any; + try { + await signTx( + api, + Market.sellAsset( + liqId, + firstCurrency, + GASP_ASSET_ID, + soldAssetAmount, + ), + testUser.keyRingPair, + ); + } catch (e) { + error = e; + } + expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); + }, + ); + + test.each(["Xyk", "StableSwap"])( + "GIVEN a singleSell WHEN a user is selling a token that is tokenValueThreshold but amount is < thresholdSet THEN  it fails on pre-validation", + async (poolType) => { + const poolAmount = threshold.muln(5); + + await Sudo.batchAsSudoFinalized( + Market.createPool( + firstCurrency, + poolAmount, + GASP_ASSET_ID, + poolAmount, + poolType, + ), + Assets.mintToken(firstCurrency, testUser, poolAmount), + ); + await updateFeeLockMetadata(sudo, null, null, null, [ - [thirdCurrency, true], + [firstCurrency, true], ]); - const liqId = await rpcGetPoolId(thirdCurrency, GASP_ASSET_ID); + const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); let error: any; try { @@ -1312,7 +1349,7 @@ describe("User has only sold asset and buy GASP", () => { liqId, firstCurrency, GASP_ASSET_ID, - soldAssetAmount, + threshold.divn(2), ), testUser.keyRingPair, ); From aa874672bb890b8ffca49c592ae5bdba6f646990 Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Wed, 30 Apr 2025 16:49:03 +0200 Subject: [PATCH 7/8] chore: add new tests --- test/parallel/market.fee.scenarios.test.ts | 291 +++++++++++++++------ 1 file changed, 213 insertions(+), 78 deletions(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index 20d57dca2..b622c9d01 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -374,9 +374,6 @@ describe("SingleSell, user has only sold asset", () => { )), Assets.mintToken(firstCurrency, testUser, threshold.muln(2)), ); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); @@ -393,21 +390,27 @@ describe("SingleSell, user has only sold asset", () => { ); test("GIVEN sold asset is not whitelisted AND sale amount > threshold THEN operation fails on client", async () => { + const [thirdCurrency] = await Assets.setupUserWithCurrencies( + sudo, + [threshold.muln(20), threshold.muln(20)], + sudo, + ); + await Sudo.batchAsSudoFinalized( ...(await addTestExtrinsic( - [firstCurrency, secondCurrency], - [true, "Xyk"], - [true, "Xyk"], + [thirdCurrency, thirdCurrency], + [false, ""], [true, "Xyk"], + [false, ""], )), - Assets.mintToken(firstCurrency, testUser, threshold.muln(2)), + Assets.mintToken(thirdCurrency, testUser, threshold.muln(2)), ); - const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); + const liqId = await rpcGetPoolId(thirdCurrency, GASP_ASSET_ID); await getSwappingTokenError( testUser, - [firstCurrency, GASP_ASSET_ID], + [thirdCurrency, GASP_ASSET_ID], liqId, threshold.muln(3).divn(2), feeLockErrors.SwapApprovalFail, @@ -1070,17 +1073,17 @@ describe("Fee checking scenarios, user has only sold asset and sold amount > use describe("User has only sold asset and buy GASP", () => { test.each(["Xyk", "StableSwap"])( - "SingleSell - GIVEN sell operation for %s pools AND sale amount > threshold THEN operation operation succeed", + "SingleSell - GIVEN sell operation for %s pools AND that is on tokenValueThreshold AND sale amount > threshold THEN operation operation succeed", async (poolType) => { const soldAssetAmount = threshold.muln(2); await Sudo.batchAsSudoFinalized( ...(await addTestExtrinsic( [firstCurrency, secondCurrency], + [false, ""], [true, poolType], - [true, poolType], - [true, poolType], + [false, ""], )), - Assets.mintToken(firstCurrency, testUser, soldAssetAmount.muln(3)), + Assets.mintToken(firstCurrency, testUser, threshold.muln(5)), ); await updateFeeLockMetadata(sudo, null, null, null, [ [firstCurrency, true], @@ -1128,30 +1131,19 @@ describe("User has only sold asset and buy GASP", () => { ); test.each(["Xyk", "StableSwap"])( - "MultiSell - GIVEN sell operation for %s pools AND sale amount > threshold THEN operation operation succeed", + "MultiSell - GIVEN sell operation for %s pools AND that is on tokenValueThreshold AND sale amount > threshold THEN operation operation succeed", async (poolType) => { const soldAssetAmount = threshold.muln(2); - const poolAmount = threshold.muln(5); await Sudo.batchAsSudoFinalized( - Market.createPool( - firstCurrency, - poolAmount, - secondCurrency, - poolAmount, - poolType, - ), - Market.createPool( - secondCurrency, - poolAmount, - GASP_ASSET_ID, - poolAmount, - poolType, - ), - Assets.mintToken(firstCurrency, testUser, poolAmount), + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [true, poolType], + [false, ""], + [true, poolType], + )), + Assets.mintToken(firstCurrency, testUser, threshold.muln(5)), ); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); + await updateFeeLockMetadata(sudo, null, null, null, [ [firstCurrency, true], ]); @@ -1211,31 +1203,19 @@ describe("User has only sold asset and buy GASP", () => { ); test.each(["Xyk", "StableSwap"])( - "GIVEN sellAsset operation for Xyk pool AND sale amount > threshold AND buying GASP THEN operation fails on client", + "GIVEN sellAsset operation for %s pool AND that is on tokenValueThreshold AND sale amount > threshold AND buying GASP THEN operation fails on client", async (poolType) => { const soldAssetAmount = threshold.muln(2); const poolAmount = threshold.muln(5); await Sudo.batchAsSudoFinalized( - Market.createPool( - firstCurrency, - poolAmount, - secondCurrency, - poolAmount, - poolType, - ), - Market.createPool( - secondCurrency, - poolAmount, - GASP_ASSET_ID, - poolAmount, - poolType, - ), + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [true, poolType], + [false, ""], + [true, poolType], + )), Assets.mintToken(firstCurrency, testUser, poolAmount), ); - - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); await updateFeeLockMetadata(sudo, null, null, null, [ [firstCurrency, true], ]); @@ -1276,7 +1256,7 @@ describe("User has only sold asset and buy GASP", () => { ); test.each(["Xyk", "StableSwap"])( - "GIVEN a singleSell for %s pool WHEN a user is selling a token that is not tokenValueThreshold it fails on pre-validation", + "GIVEN a singleSell for %s pool WHEN a user is selling a token AND that is not tokenValueThreshold it fails on pre-validation", async (poolType) => { const [thirdCurrency] = await Assets.setupUserWithCurrencies( sudo, @@ -1284,18 +1264,14 @@ describe("User has only sold asset and buy GASP", () => { sudo, ); - const soldAssetAmount = threshold.muln(2); - const poolAmount = threshold.muln(5); - await Sudo.batchAsSudoFinalized( - Market.createPool( - thirdCurrency, - poolAmount, - GASP_ASSET_ID, - poolAmount, - poolType, - ), - Assets.mintToken(thirdCurrency, testUser, poolAmount), + ...(await addTestExtrinsic( + [thirdCurrency, thirdCurrency], + [false, ""], + [true, poolType], + [false, ""], + )), + Assets.mintToken(firstCurrency, testUser, threshold.muln(5)), ); const liqId = await rpcGetPoolId(thirdCurrency, GASP_ASSET_ID); @@ -1308,7 +1284,41 @@ describe("User has only sold asset and buy GASP", () => { liqId, firstCurrency, GASP_ASSET_ID, - soldAssetAmount, + threshold.muln(2), + ), + testUser.keyRingPair, + ); + } catch (e) { + error = e; + } + expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); + }, + ); + + test.each(["Xyk", "StableSwap"])( + "GIVEN a singleSell operation for %s pool WHEN a user is selling a token AND that is on tokenValueThreshold but amount is < thresholdSet THEN  it fails on pre-validation", + async (poolType) => { + await Sudo.batchAsSudoFinalized( + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [false, ""], + [true, poolType], + [false, ""], + )), + Assets.mintToken(firstCurrency, testUser, threshold.muln(5)), + ); + + const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); + + let error: any; + try { + await signTx( + api, + Market.sellAsset( + liqId, + firstCurrency, + GASP_ASSET_ID, + threshold.divn(2), ), testUser.keyRingPair, ); @@ -1320,33 +1330,158 @@ describe("User has only sold asset and buy GASP", () => { ); test.each(["Xyk", "StableSwap"])( - "GIVEN a singleSell WHEN a user is selling a token that is tokenValueThreshold but amount is < thresholdSet THEN  it fails on pre-validation", + "GIVEN a multiSell for %s pool WHEN a user is selling a token AND that is not tokenValueThreshold it fails on pre-validation", async (poolType) => { const poolAmount = threshold.muln(5); + const [thirdCurrency, forthCurrency] = + await Assets.setupUserWithCurrencies( + sudo, + [threshold.muln(20), threshold.muln(20)], + sudo, + ); await Sudo.batchAsSudoFinalized( - Market.createPool( - firstCurrency, - poolAmount, - GASP_ASSET_ID, - poolAmount, - poolType, - ), + ...(await addTestExtrinsic( + [thirdCurrency, forthCurrency], + [true, poolType], + [false, ""], + [true, poolType], + )), Assets.mintToken(firstCurrency, testUser, poolAmount), ); - await updateFeeLockMetadata(sudo, null, null, null, [ - [firstCurrency, true], - ]); + const liqId1 = await rpcGetPoolId(thirdCurrency, forthCurrency); + const liqId2 = await rpcGetPoolId(forthCurrency, GASP_ASSET_ID); - const liqId = await rpcGetPoolId(firstCurrency, GASP_ASSET_ID); + let error: any; + try { + await signTx( + api, + Market.sellAsset( + [liqId1, liqId2], + thirdCurrency, + GASP_ASSET_ID, + threshold.muln(2), + ), + testUser.keyRingPair, + ); + } catch (e) { + error = e; + } + expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); + }, + ); + + test.each(["Xyk", "StableSwap"])( + "GIVEN a multiSell operation for %s pool WHEN a user is selling a token AND that is on tokenValueThreshold AND amount is < thresholdSet THEN  it fails on pre-validation", + async (poolType) => { + const poolAmount = threshold.muln(5); + + await Sudo.batchAsSudoFinalized( + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [true, poolType], + [false, ""], + [true, poolType], + )), + Assets.mintToken(firstCurrency, testUser, poolAmount), + ); + + const liqId1 = await rpcGetPoolId(firstCurrency, secondCurrency); + const liqId2 = await rpcGetPoolId(secondCurrency, GASP_ASSET_ID); let error: any; try { await signTx( api, Market.sellAsset( - liqId, + [liqId1, liqId2], + firstCurrency, + GASP_ASSET_ID, + threshold.divn(2), + ), + testUser.keyRingPair, + ); + } catch (e) { + error = e; + } + expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); + }, + ); + + test.each(["Xyk", "StableSwap"])( + "GIVEN a multiBuy operation for %s WHEN a user is selling a token that is not tokenValueThreshold it fails on pre-validation", + async (poolType) => { + const poolAmount = threshold.muln(5); + const [thirdCurrency, forthCurrency] = + await Assets.setupUserWithCurrencies( + sudo, + [threshold.muln(20), threshold.muln(20)], + sudo, + ); + + await Sudo.batchAsSudoFinalized( + ...(await addTestExtrinsic( + [thirdCurrency, forthCurrency], + [true, poolType], + [false, ""], + [true, poolType], + )), + Assets.mintToken(thirdCurrency, testUser, poolAmount), + ); + + const liqId1 = await rpcGetPoolId(thirdCurrency, forthCurrency); + const liqId2 = await rpcGetPoolId(forthCurrency, GASP_ASSET_ID); + + let error: any; + try { + await signTx( + api, + await Market.buyAsset( + [liqId1, liqId2], + thirdCurrency, + GASP_ASSET_ID, + threshold.muln(2), + ), + testUser.keyRingPair, + ); + } catch (e) { + error = e; + } + expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); + }, + ); + + test.each(["Xyk", "StableSwap"])( + "GIVEN a multiBuy operation for %s WHEN a user is selling a token that is on tokenValueThreshold but amount is < thresholdSet THEN it fails on pre-validation", + async (poolType) => { + const poolAmount = threshold.muln(5); + const [firstCurrency, secondCurrency] = + await Assets.setupUserWithCurrencies( + sudo, + [threshold.muln(20), threshold.muln(20)], + sudo, + ); + + await Sudo.batchAsSudoFinalized( + ...(await addTestExtrinsic( + [firstCurrency, secondCurrency], + [true, poolType], + [false, ""], + [true, poolType], + )), + Assets.mintToken(firstCurrency, testUser, poolAmount), + ); + + const liqId1 = await rpcGetPoolId(firstCurrency, secondCurrency); + const liqId2 = await rpcGetPoolId(secondCurrency, GASP_ASSET_ID); + + let error: any; + try { + await signTx( + api, + await Market.buyAsset( + [liqId1, liqId2], firstCurrency, GASP_ASSET_ID, threshold.divn(2), From f477b37574f8723d905bd3ca232930fe94d538e4 Mon Sep 17 00:00:00 2001 From: AlexChetverov Date: Thu, 1 May 2025 16:25:43 +0200 Subject: [PATCH 8/8] chore: last changes --- test/parallel/market.fee.scenarios.test.ts | 70 +++++++--------------- 1 file changed, 23 insertions(+), 47 deletions(-) diff --git a/test/parallel/market.fee.scenarios.test.ts b/test/parallel/market.fee.scenarios.test.ts index b622c9d01..7e1605e99 100644 --- a/test/parallel/market.fee.scenarios.test.ts +++ b/test/parallel/market.fee.scenarios.test.ts @@ -1071,10 +1071,10 @@ describe("Fee checking scenarios, user has only sold asset and sold amount > use }); }); -describe("User has only sold asset and buy GASP", () => { - test.each(["Xyk", "StableSwap"])( - "SingleSell - GIVEN sell operation for %s pools AND that is on tokenValueThreshold AND sale amount > threshold THEN operation operation succeed", - async (poolType) => { +describe.each(["Xyk", "StableSwap"])( + "User has only sold asset in %s pool and buy GASP, ", + (poolType) => { + test("SingleSell - GIVEN sell operation AND that is on tokenValueThreshold AND sale amount > threshold THEN operation operation succeed", async () => { const soldAssetAmount = threshold.muln(2); await Sudo.batchAsSudoFinalized( ...(await addTestExtrinsic( @@ -1127,12 +1127,9 @@ describe("User has only sold asset and buy GASP", () => { expect(stringToBN(filteredEvent[0].swaps[0].amountIn)).bnEqual( soldAssetAmount.muln(997).divn(1000), ); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "MultiSell - GIVEN sell operation for %s pools AND that is on tokenValueThreshold AND sale amount > threshold THEN operation operation succeed", - async (poolType) => { + test("MultiSell - GIVEN sell operation AND that is on tokenValueThreshold AND sale amount > threshold THEN operation operation succeed", async () => { const soldAssetAmount = threshold.muln(2); await Sudo.batchAsSudoFinalized( ...(await addTestExtrinsic( @@ -1199,12 +1196,9 @@ describe("User has only sold asset and buy GASP", () => { expect(stringToBN(filteredEvent[0].swaps[0].amountIn)).bnEqual( soldAssetAmount.muln(997).divn(1000), ); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "GIVEN sellAsset operation for %s pool AND that is on tokenValueThreshold AND sale amount > threshold AND buying GASP THEN operation fails on client", - async (poolType) => { + test("GIVEN sellAsset operation AND that is on tokenValueThreshold AND sale amount > threshold AND buying GASP THEN operation fails on client", async () => { const soldAssetAmount = threshold.muln(2); const poolAmount = threshold.muln(5); await Sudo.batchAsSudoFinalized( @@ -1252,12 +1246,9 @@ describe("User has only sold asset and buy GASP", () => { expect(userAmountBefore[0].free.sub(userAmountAfter[0].free)).bnEqual( soldAssetAmount.muln(3).divn(1000), ); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "GIVEN a singleSell for %s pool WHEN a user is selling a token AND that is not tokenValueThreshold it fails on pre-validation", - async (poolType) => { + test("GIVEN a singleSell WHEN a user is selling a token AND that is not tokenValueThreshold it fails on pre-validation", async () => { const [thirdCurrency] = await Assets.setupUserWithCurrencies( sudo, [threshold.muln(20)], @@ -1292,12 +1283,9 @@ describe("User has only sold asset and buy GASP", () => { error = e; } expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "GIVEN a singleSell operation for %s pool WHEN a user is selling a token AND that is on tokenValueThreshold but amount is < thresholdSet THEN  it fails on pre-validation", - async (poolType) => { + test("GIVEN a singleSell operation WHEN a user is selling a token AND that is on tokenValueThreshold but amount is < thresholdSet THEN  it fails on pre-validation", async () => { await Sudo.batchAsSudoFinalized( ...(await addTestExtrinsic( [firstCurrency, secondCurrency], @@ -1326,12 +1314,9 @@ describe("User has only sold asset and buy GASP", () => { error = e; } expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "GIVEN a multiSell for %s pool WHEN a user is selling a token AND that is not tokenValueThreshold it fails on pre-validation", - async (poolType) => { + test("GIVEN a multiSell WHEN a user is selling a token AND that is not tokenValueThreshold it fails on pre-validation", async () => { const poolAmount = threshold.muln(5); const [thirdCurrency, forthCurrency] = await Assets.setupUserWithCurrencies( @@ -1369,12 +1354,9 @@ describe("User has only sold asset and buy GASP", () => { error = e; } expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "GIVEN a multiSell operation for %s pool WHEN a user is selling a token AND that is on tokenValueThreshold AND amount is < thresholdSet THEN  it fails on pre-validation", - async (poolType) => { + test("GIVEN a multiSell operation WHEN a user is selling a token AND that is on tokenValueThreshold AND amount is < thresholdSet THEN  it fails on pre-validation", async () => { const poolAmount = threshold.muln(5); await Sudo.batchAsSudoFinalized( @@ -1406,12 +1388,9 @@ describe("User has only sold asset and buy GASP", () => { error = e; } expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "GIVEN a multiBuy operation for %s WHEN a user is selling a token that is not tokenValueThreshold it fails on pre-validation", - async (poolType) => { + test("GIVEN a multiBuy operation WHEN a user is selling a token that is not tokenValueThreshold it fails on pre-validation", async () => { const poolAmount = threshold.muln(5); const [thirdCurrency, forthCurrency] = await Assets.setupUserWithCurrencies( @@ -1449,12 +1428,9 @@ describe("User has only sold asset and buy GASP", () => { error = e; } expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); - }, - ); + }); - test.each(["Xyk", "StableSwap"])( - "GIVEN a multiBuy operation for %s WHEN a user is selling a token that is on tokenValueThreshold but amount is < thresholdSet THEN it fails on pre-validation", - async (poolType) => { + test("GIVEN a multiBuy operation WHEN a user is selling a token that is on tokenValueThreshold but amount is < thresholdSet THEN it fails on pre-validation", async () => { const poolAmount = threshold.muln(5); const [firstCurrency, secondCurrency] = await Assets.setupUserWithCurrencies( @@ -1492,6 +1468,6 @@ describe("User has only sold asset and buy GASP", () => { error = e; } expect(error.data).toEqual(feeLockErrors.SwapApprovalFail); - }, - ); -}); + }); + }, +);