From c60a084669a751ee3dd35eb541b127543c22d849 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 13:19:39 +0100 Subject: [PATCH 01/67] chore: impr ffee - return --- .../src/helpers/orders/getFrontendFee.test.ts | 98 +++++++++++++------ .../swap/src/helpers/orders/getFrontendFee.ts | 38 +++---- packages/swap/src/translators/constants.ts | 13 +-- 3 files changed, 94 insertions(+), 55 deletions(-) diff --git a/packages/swap/src/helpers/orders/getFrontendFee.test.ts b/packages/swap/src/helpers/orders/getFrontendFee.test.ts index 3287a54c8e..acf04e53d3 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.test.ts +++ b/packages/swap/src/helpers/orders/getFrontendFee.test.ts @@ -45,8 +45,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: Quantities.zero, + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: Quantities.zero, + }, + discountTier: undefined, }) }) @@ -68,8 +71,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA + }, + discountTier: milkHoldersDiscountTiers[2], }) }) @@ -91,8 +97,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1 = 1.025 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1 = 1.025 ADA + }, + discountTier: milkHoldersDiscountTiers[1], }) }) @@ -114,8 +123,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1 = 1.02 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1 = 1.02 ADA + }, + discountTier: milkHoldersDiscountTiers[0], }) }) }) @@ -139,8 +151,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: Quantities.zero, + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: Quantities.zero, + }, + discountTier: undefined, }) }) @@ -162,8 +177,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA + }, + discountTier: milkHoldersDiscountTiers[2], }) }) @@ -185,8 +203,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1 = 1.025 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1 = 1.025 ADA + }, + discountTier: milkHoldersDiscountTiers[1], }) }) @@ -208,8 +229,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1= 1.02 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1= 1.02 ADA + }, + discountTier: milkHoldersDiscountTiers[0], }) }) }) @@ -231,8 +255,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: Quantities.zero, + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: Quantities.zero, + }, + discountTier: undefined, }) }) @@ -253,8 +280,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: Quantities.zero, + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: Quantities.zero, + }, + discountTier: undefined, }) }) @@ -286,8 +316,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: Quantities.zero, + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: Quantities.zero, + }, + discountTier: undefined, }) }) @@ -317,8 +350,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA + }, + discountTier: milkHoldersDiscountTiers[2], }) }) @@ -348,8 +384,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1= 1.025 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1= 1.025 ADA + }, + discountTier: milkHoldersDiscountTiers[1], }) }) @@ -379,8 +418,11 @@ describe('getFrontendFee', () => { }) // assert expect(fee).toEqual({ - tokenId: primaryTokenInfo.id, - quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1 = 1.02 ADA + frontendFee: { + tokenId: primaryTokenInfo.id, + quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1 = 1.02 ADA + }, + discountTier: milkHoldersDiscountTiers[0], }) }) }) diff --git a/packages/swap/src/helpers/orders/getFrontendFee.ts b/packages/swap/src/helpers/orders/getFrontendFee.ts index f2af647210..b3f0ef305f 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.ts +++ b/packages/swap/src/helpers/orders/getFrontendFee.ts @@ -3,7 +3,7 @@ import BigNumber from 'bignumber.js' import {Quantities} from '../../utils/quantities' import { - DiscountTier, + SwapDiscountTier, milkHoldersDiscountTiers, } from '../../translators/constants' import {asQuantity} from '../../utils/asQuantity' @@ -23,8 +23,11 @@ export const getFrontendFee = ({ sellInPrimaryTokenValue: Balance.Amount buyInPrimaryTokenValue: Balance.Amount primaryTokenInfo: Balance.TokenInfo - discountTiers?: ReadonlyArray -}): Balance.Amount => { + discountTiers?: ReadonlyArray +}): Readonly<{ + frontendFee: Balance.Amount + discountTier?: SwapDiscountTier | undefined +}> => { // discover trade value in ADA (sell/buy/max by pairing) // it should range around 50/50 const maxPrimaryValueSellBuy = Quantities.max( @@ -39,19 +42,17 @@ export const getFrontendFee = ({ : maxPrimaryValueSellBuy // identify the discount - const defaultTier = discountTiers[discountTiers.length - 1] // expects max fee as last record - const discountTier = - discountTiers.find( - (tier) => - Quantities.isGreaterThanOrEqualTo( - milkBalance, - tier.secondaryTokenBalanceThreshold, - ) && - Quantities.isGreaterThanOrEqualTo( - primaryTokenBiggerTradingValue, - tier.primaryTokenValueThreshold, - ), - ) ?? defaultTier + const discountTier = discountTiers.find( + (tier) => + Quantities.isGreaterThanOrEqualTo( + milkBalance, + tier.secondaryTokenBalanceThreshold, + ) && + Quantities.isGreaterThanOrEqualTo( + primaryTokenBiggerTradingValue, + tier.primaryTokenValueThreshold, + ), + ) // calculate the fee const fee = asQuantity( @@ -61,5 +62,8 @@ export const getFrontendFee = ({ .plus(discountTier?.fixedFee ?? 0), ) - return {tokenId: primaryTokenInfo.id, quantity: fee} + return { + frontendFee: {tokenId: primaryTokenInfo.id, quantity: fee}, + discountTier, + } as const } diff --git a/packages/swap/src/translators/constants.ts b/packages/swap/src/translators/constants.ts index 6097c9c9dc..73f4bb5b0e 100644 --- a/packages/swap/src/translators/constants.ts +++ b/packages/swap/src/translators/constants.ts @@ -12,16 +12,16 @@ export const supportedProviders: ReadonlyArray = [ 'vyfi', ] as const -export type DiscountTier = { +export type SwapDiscountTier = Readonly<{ primaryTokenValueThreshold: Balance.Quantity // primary token trade value threshold secondaryTokenBalanceThreshold: Balance.Quantity // secodary token balance (holding) variableFeeMultiplier: number variableFeeVisual: number fixedFee: Balance.Quantity -} +}> // table of discounts based on MILK token holdings + value in ADA -export const milkHoldersDiscountTiers: ReadonlyArray = [ +export const milkHoldersDiscountTiers: ReadonlyArray = [ // MILK 500+, VALUE ADA 100+, FFEE = 1 ADA + 0.020 % { primaryTokenValueThreshold: asQuantity(100_000_000), @@ -47,13 +47,6 @@ export const milkHoldersDiscountTiers: ReadonlyArray = [ fixedFee: asQuantity(1_000_000), }, // VALUE ADA 0-99, FFEE = 0% - { - primaryTokenValueThreshold: Quantities.zero, - secondaryTokenBalanceThreshold: Quantities.zero, - variableFeeMultiplier: 0.0, - variableFeeVisual: 0.0, - fixedFee: Quantities.zero, - }, ] as const export const milkTokenId = { From 59bb64f7b76a4247e00551148f15f56da8903c11 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:12:02 +0100 Subject: [PATCH 02/67] refactor: sonarqube complexity --- .../src/helpers/orders/getFrontendFee.test.ts | 2 -- .../swap/src/helpers/orders/getFrontendFee.ts | 31 ++++++++++--------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/swap/src/helpers/orders/getFrontendFee.test.ts b/packages/swap/src/helpers/orders/getFrontendFee.test.ts index acf04e53d3..26d12acf0b 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.test.ts +++ b/packages/swap/src/helpers/orders/getFrontendFee.test.ts @@ -274,8 +274,6 @@ describe('getFrontendFee', () => { sellAmount: notPrimaryTokenAmount, buyAmount: buyPrimaryAmountOver99, milkBalance: '999999999999999', - sellInPrimaryTokenValue: buyPrimaryAmountOver99, - buyInPrimaryTokenValue: buyPrimaryAmountOver99, primaryTokenInfo, }) // assert diff --git a/packages/swap/src/helpers/orders/getFrontendFee.ts b/packages/swap/src/helpers/orders/getFrontendFee.ts index b3f0ef305f..4dd67bbd56 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.ts +++ b/packages/swap/src/helpers/orders/getFrontendFee.ts @@ -12,34 +12,37 @@ export const getFrontendFee = ({ sellAmount, buyAmount, milkBalance, + primaryTokenInfo, sellInPrimaryTokenValue, buyInPrimaryTokenValue, - primaryTokenInfo, discountTiers = milkHoldersDiscountTiers, }: { sellAmount: Balance.Amount buyAmount: Balance.Amount milkBalance: Balance.Quantity - sellInPrimaryTokenValue: Balance.Amount - buyInPrimaryTokenValue: Balance.Amount primaryTokenInfo: Balance.TokenInfo discountTiers?: ReadonlyArray + // not implemented yet (for now only ffee is added only if ADA is one of the pair) + sellInPrimaryTokenValue?: Balance.Amount + buyInPrimaryTokenValue?: Balance.Amount }): Readonly<{ frontendFee: Balance.Amount - discountTier?: SwapDiscountTier | undefined + discountTier: SwapDiscountTier | undefined }> => { // discover trade value in ADA (sell/buy/max by pairing) // it should range around 50/50 const maxPrimaryValueSellBuy = Quantities.max( - sellInPrimaryTokenValue.quantity, - buyInPrimaryTokenValue.quantity, + sellInPrimaryTokenValue?.quantity ?? Quantities.zero, + buyInPrimaryTokenValue?.quantity ?? Quantities.zero, ) - const primaryTokenBiggerTradingValue = - sellAmount.tokenId === primaryTokenInfo.id - ? sellAmount.quantity - : buyAmount.tokenId === primaryTokenInfo.id - ? buyInPrimaryTokenValue.quantity - : maxPrimaryValueSellBuy + let primaryTokenBiggerPairValue: Balance.Quantity + if (sellAmount.tokenId === primaryTokenInfo.id) { + primaryTokenBiggerPairValue = sellAmount.quantity + } else if (buyAmount.tokenId === primaryTokenInfo.id) { + primaryTokenBiggerPairValue = buyAmount.quantity + } else { + primaryTokenBiggerPairValue = maxPrimaryValueSellBuy + } // identify the discount const discountTier = discountTiers.find( @@ -49,14 +52,14 @@ export const getFrontendFee = ({ tier.secondaryTokenBalanceThreshold, ) && Quantities.isGreaterThanOrEqualTo( - primaryTokenBiggerTradingValue, + primaryTokenBiggerPairValue, tier.primaryTokenValueThreshold, ), ) // calculate the fee const fee = asQuantity( - new BigNumber(primaryTokenBiggerTradingValue) + new BigNumber(primaryTokenBiggerPairValue) .times(discountTier?.variableFeeMultiplier ?? 0) .integerValue(BigNumber.ROUND_UP) .plus(discountTier?.fixedFee ?? 0), From 5c37c34fcecdda27cb15298c266acfe3252bf9e4 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 20:59:17 +0100 Subject: [PATCH 03/67] wip: order calcs --- .../helpers/orders/makeOrderCalculations.ts | 77 ++++++++++ .../src/translators/reactjs/state/state.ts | 132 ++++++++++++++++++ packages/types/src/helpers/types.ts | 3 + 3 files changed, 212 insertions(+) create mode 100644 packages/swap/src/helpers/orders/makeOrderCalculations.ts diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts new file mode 100644 index 0000000000..46fda6cbf5 --- /dev/null +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -0,0 +1,77 @@ +import {Balance, Swap, Writable} from '@yoroi/types' +import { + SwapCreateOrderActionType, + SwapOrderCalulation, +} from '../../translators/reactjs/state/state' +import {getQuantityWithSlippage} from './getQuantityWithSlippage' +import {Quantities} from '../../utils/quantities' + +export const makeOrderCalculations = ({ + orderData, + pools, + primaryTokenId, + action, +}: Readonly<{ + orderData: Swap.CreateOrderData + pools: Array + sellAmount: Balance.Amount + buyAmount: Balance.Amount + slippage: number + primaryTokenId: Balance.TokenInfo['id'] + action: + | SwapCreateOrderActionType.SellQuantityChanged + | SwapCreateOrderActionType.SellTokenIdChanged + | SwapCreateOrderActionType.BuyQuantityChanged + | SwapCreateOrderActionType.BuyTokenIdChanged + | SwapCreateOrderActionType.SlippageChanged + | SwapCreateOrderActionType.PoolPairsChanged +}>) => { + console.log(action) + const result: Array = [] + + pools.forEach((pool) => { + let orderCalculation: Writable + + orderCalculation = { + cost: { + batcherFee: { + tokenId: primaryTokenId, + quantity: Quantities.zero, + }, + frontendFeeInfo: { + fee: { + tokenId: primaryTokenId, + quantity: Quantities.zero, + }, + tier: undefined, + }, + deposit: pool.deposit, + liquidityFee: { + tokenId: orderData.amounts.sell.tokenId, + quantity: Quantities.zero, + }, + }, + buyAmountWithSlippage: { + quantity: getQuantityWithSlippage( + orderData.amounts.buy.quantity, + orderData.slippage, + ), + tokenId: orderData.amounts.buy.tokenId, + }, + sell: { + price: '', + priceDifference: '', + priceWithFees: '', + priceWithFeesAndSlippage: '', + priceWithSlippage: '', + }, + pool, + } + + result.push(orderCalculation) + + // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? + }) + + return result +} diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 67343f8b81..f5e1ede249 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -5,6 +5,29 @@ import {getBuyAmount} from '../../../helpers/orders/getBuyAmount' import {getSellAmount} from '../../../helpers/orders/getSellAmount' import {getMarketPrice} from '../../../helpers/orders/getMarketPrice' import {Quantities} from '../../../utils/quantities' +import {SwapDiscountTier} from '../../../translators/constants' +import _ from 'lodash' + +export type SwapOrderCalulation = Readonly<{ + pool: Swap.Pool + sell: { + price: string + priceWithFees: string + priceDifference: string + priceWithSlippage: string + priceWithFeesAndSlippage: string + } + buyAmountWithSlippage: Balance.Amount + cost: { + liquidityFee: Balance.Amount + deposit: Balance.Amount + batcherFee: Balance.Amount + frontendFeeInfo: { + tier: SwapDiscountTier | undefined + fee: Balance.Amount + } + } +}> export type SwapState = Readonly<{ createOrder: Omit & { @@ -13,6 +36,8 @@ export type SwapState = Readonly<{ datum: string datumHash: string selectedPool?: Swap.Pool + // + calculations: Array } unsignedTx: any }> @@ -27,6 +52,12 @@ export type SwapCreateOrderActions = Readonly<{ switchTokens: () => void resetQuantities: () => void limitPriceChanged: (limitPrice: Balance.Quantity) => void + // + sellQuantityChanged: (quantity: Balance.Quantity) => void + buyQuantityChanged: (quantity: Balance.Quantity) => void + sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void + buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void + poolPairsChanged: (pools: ReadonlyArray) => void }> export enum SwapCreateOrderActionType { @@ -40,6 +71,12 @@ export enum SwapCreateOrderActionType { SwitchTokens = 'switchTokens', ResetQuantities = 'resetQuantities', LimitPriceChanged = 'limitPriceChanged', + // + SellQuantityChanged = 'sellQuantityChanged', + BuyQuantityChanged = 'buyQuantityChanged', + SellTokenIdChanged = 'sellTokenIdChanged', + BuyTokenIdChanged = 'buyTokenIdChanged', + PoolPairsChanged = 'poolPairsChanged', } export type SwapCreateOrderAction = @@ -77,6 +114,27 @@ export type SwapCreateOrderAction = } | {type: SwapCreateOrderActionType.SwitchTokens} | {type: SwapCreateOrderActionType.ResetQuantities} + // + | { + type: SwapCreateOrderActionType.SellQuantityChanged + quantity: Balance.Quantity + } + | { + type: SwapCreateOrderActionType.BuyQuantityChanged + quantity: Balance.Quantity + } + | { + type: SwapCreateOrderActionType.SellTokenIdChanged + tokenId: Balance.TokenInfo['id'] + } + | { + type: SwapCreateOrderActionType.BuyTokenIdChanged + tokenId: Balance.TokenInfo['id'] + } + | { + type: SwapCreateOrderActionType.PoolPairsChanged + pools: ReadonlyArray + } export type SwapActions = Readonly<{ // TODO: import from @yoroi/common unsignedTx type @@ -133,6 +191,8 @@ export const defaultSwapState: SwapState = { limitPrice: Quantities.zero, marketPrice: Quantities.zero, selectedPool: undefined, + // + calculations: [], }, unsignedTx: undefined, } as const @@ -147,6 +207,12 @@ const defaultSwapCreateOrderActions: SwapCreateOrderActions = { switchTokens: missingInit, resetQuantities: missingInit, limitPriceChanged: missingInit, + + sellQuantityChanged: missingInit, + buyQuantityChanged: missingInit, + sellTokenIdChanged: missingInit, + buyTokenIdChanged: missingInit, + poolPairsChanged: missingInit, } as const const defaultStateActions: SwapActions = { @@ -178,6 +244,7 @@ const createOrderReducer = ( : undefined, ) break + case SwapCreateOrderActionType.SellAmountChanged: draft.createOrder.amounts.sell = action.amount if ( @@ -195,6 +262,7 @@ const createOrderReducer = ( ) } break + case SwapCreateOrderActionType.BuyAmountChanged: draft.createOrder.amounts.buy = action.amount if ( @@ -212,6 +280,7 @@ const createOrderReducer = ( ) } break + case SwapCreateOrderActionType.SelectedPoolChanged: draft.createOrder.selectedPool = action.pool if (action.pool === undefined) { @@ -232,14 +301,17 @@ const createOrderReducer = ( ) } break + case SwapCreateOrderActionType.SlippageChanged: draft.createOrder.slippage = action.slippage break + case SwapCreateOrderActionType.TxPayloadChanged: draft.createOrder.datum = action.txPayload.datum draft.createOrder.datumHash = action.txPayload.datumHash draft.createOrder.address = action.txPayload.contractAddress break + case SwapCreateOrderActionType.SwitchTokens: draft.createOrder.amounts = { sell: state.createOrder.amounts.buy, @@ -275,6 +347,7 @@ const createOrderReducer = ( ) } break + case SwapCreateOrderActionType.ResetQuantities: draft.createOrder.amounts = { sell: { @@ -288,6 +361,7 @@ const createOrderReducer = ( } draft.createOrder.limitPrice = state.createOrder.marketPrice break + case SwapCreateOrderActionType.LimitPriceChanged: draft.createOrder.limitPrice = action.limitPrice @@ -299,9 +373,67 @@ const createOrderReducer = ( action.limitPrice, ) break + + // + case SwapCreateOrderActionType.SellQuantityChanged: + draft.createOrder.amounts.sell.quantity = action.quantity + break + + case SwapCreateOrderActionType.BuyQuantityChanged: + draft.createOrder.amounts.buy.quantity = action.quantity + break + + case SwapCreateOrderActionType.SellTokenIdChanged: + draft.createOrder.amounts.sell.tokenId = action.tokenId + break + + case SwapCreateOrderActionType.BuyTokenIdChanged: + draft.createOrder.amounts.buy.tokenId = action.tokenId + break + + case SwapCreateOrderActionType.PoolPairsChanged: + draft.createOrder.calculations = action.pools.map((pool) => { + return { + buyAmountWithSlippage: { + quantity: Quantities.zero, + tokenId: state.createOrder.amounts.buy.tokenId, + }, + sell: { + price: '', + priceDifference: '', + priceWithFees: '', + priceWithFeesAndSlippage: '', + priceWithSlippage: '', + }, + cost: { + batcherFee: { + quantity: Quantities.zero, + tokenId: state.createOrder.amounts.buy.tokenId, + }, + deposit: { + quantity: Quantities.zero, + tokenId: state.createOrder.amounts.buy.tokenId, + }, + liquidityFee: { + quantity: Quantities.zero, + tokenId: state.createOrder.amounts.buy.tokenId, + }, + frontendFeeInfo: { + tier: undefined, + fee: { + quantity: Quantities.zero, + tokenId: state.createOrder.amounts.buy.tokenId, + }, + }, + }, + pool, + } + }) + break } }) } + const swapReducer = (state: SwapState, action: SwapAction) => { return produce(state, (draft) => { switch (action.type) { diff --git a/packages/types/src/helpers/types.ts b/packages/types/src/helpers/types.ts index c99b0be4f5..fdbf15d614 100644 --- a/packages/types/src/helpers/types.ts +++ b/packages/types/src/helpers/types.ts @@ -1 +1,4 @@ export type Nullable = T | null | undefined +export type Writable = { + -readonly [P in keyof T]: T[P] extends object ? Writable : T[P] +} From 47d80333d0705364fb173271359d0d880245edbc Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 21:40:39 +0100 Subject: [PATCH 04/67] wip: liquidity prov fee + tests --- .../orders/getLiquidityProviderFee.test.ts | 45 +++++++++++++++++++ .../helpers/orders/makeOrderCalculations.ts | 13 ++---- 2 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts diff --git a/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts b/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts new file mode 100644 index 0000000000..63ccc03b78 --- /dev/null +++ b/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts @@ -0,0 +1,45 @@ +import {Quantities} from '../../utils/quantities' +import {getLiquidityProviderFee} from './getLiquidityProviderFee' +import {asQuantity} from '../../utils/asQuantity' + +describe('getLiquidityProviderFee', () => { + it('should return zero when sell quantity is zero', () => { + const result = getLiquidityProviderFee('0.03', { + tokenId: 'testToken', + quantity: Quantities.zero, + }) + + expect(result).toEqual({ + tokenId: 'testToken', + quantity: Quantities.zero, + }) + }) + + it('should calculate provider fee correctly based on sell side', () => { + const expectedFee = '300' + + const result = getLiquidityProviderFee('0.03', { + tokenId: 'testToken', + quantity: '1000000', + }) + + expect(result).toEqual({ + tokenId: 'testToken', + quantity: asQuantity(expectedFee), + }) + }) + + it('should calculate fee ceil up', () => { + const expectedFee = '66' + + const result = getLiquidityProviderFee('66.666666', { + tokenId: 'testToken', + quantity: '99', + }) + + expect(result).toEqual({ + tokenId: 'testToken', + quantity: asQuantity(expectedFee), + }) + }) +}) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 46fda6cbf5..a711db17e2 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -5,6 +5,7 @@ import { } from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' +import {getLiquidityProviderFee} from './getLiquidityProviderFee' export const makeOrderCalculations = ({ orderData, @@ -34,10 +35,8 @@ export const makeOrderCalculations = ({ orderCalculation = { cost: { - batcherFee: { - tokenId: primaryTokenId, - quantity: Quantities.zero, - }, + batcherFee: pool.batcherFee, + deposit: pool.deposit, frontendFeeInfo: { fee: { tokenId: primaryTokenId, @@ -45,11 +44,7 @@ export const makeOrderCalculations = ({ }, tier: undefined, }, - deposit: pool.deposit, - liquidityFee: { - tokenId: orderData.amounts.sell.tokenId, - quantity: Quantities.zero, - }, + liquidityFee: getLiquidityProviderFee(pool.fee, orderData.amounts.sell), }, buyAmountWithSlippage: { quantity: getQuantityWithSlippage( From 497d336260a335dd7cc343d6e335f6a868484783 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 22:33:23 +0100 Subject: [PATCH 05/67] wip: frontend fee + lptoken --- .../src/helpers/orders/getFrontendFee.test.ts | 227 +++++++++--------- .../swap/src/helpers/orders/getFrontendFee.ts | 43 ++-- .../helpers/orders/getQuantityWithSlippage.ts | 11 +- .../helpers/orders/makeOrderCalculations.ts | 46 ++-- .../src/translators/reactjs/state/state.ts | 26 +- 5 files changed, 195 insertions(+), 158 deletions(-) diff --git a/packages/swap/src/helpers/orders/getFrontendFee.test.ts b/packages/swap/src/helpers/orders/getFrontendFee.test.ts index 26d12acf0b..001724a096 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.test.ts +++ b/packages/swap/src/helpers/orders/getFrontendFee.test.ts @@ -6,20 +6,7 @@ import {Quantities} from '../../utils/quantities' import {asQuantity} from '../../utils/asQuantity' describe('getFrontendFee', () => { - const primaryTokenInfo: Balance.TokenInfo = { - id: '', - decimals: 6, - description: 'primary', - fingerprint: '', - image: '', - group: '', - icon: '', - kind: 'ft', - name: 'ttADA', - symbol: 'ttADA', - ticker: 'ttADA', - metadatas: {}, - } + const primaryTokenId = 'primary.token' const notPrimaryTokenAmount: Balance.Amount = { tokenId: 'not.primary.token', @@ -29,24 +16,24 @@ describe('getFrontendFee', () => { describe('selling side is primary token', () => { it('< 100 and whatever milk in balance', () => { // arrange - const sellAmount: Balance.Amount = { - tokenId: primaryTokenInfo.id, + const sell: Balance.Amount = { + tokenId: primaryTokenId, quantity: asQuantity(99_999_999), } // act const fee = getFrontendFee({ - sellAmount: sellAmount, - buyAmount: notPrimaryTokenAmount, - sellInPrimaryTokenValue: sellAmount, - milkBalance: '999999999999999999', - buyInPrimaryTokenValue: sellAmount, - primaryTokenInfo, + sell: sell, + buy: notPrimaryTokenAmount, + sellInPrimaryTokenValue: sell, + lpTokenHeld: {tokenId: 'lp.token', quantity: '999999999999999999'}, + buyInPrimaryTokenValue: sell, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: Quantities.zero, }, discountTier: undefined, @@ -56,23 +43,23 @@ describe('getFrontendFee', () => { it('>= 100 and milk in balance = 0', () => { // arrange const sellPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: sellPrimaryAmountOver99, - buyAmount: notPrimaryTokenAmount, + sell: sellPrimaryAmountOver99, + buy: notPrimaryTokenAmount, sellInPrimaryTokenValue: sellPrimaryAmountOver99, - milkBalance: Quantities.zero, + lpTokenHeld: {tokenId: 'lp.token', quantity: Quantities.zero}, buyInPrimaryTokenValue: sellPrimaryAmountOver99, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA }, discountTier: milkHoldersDiscountTiers[2], @@ -82,23 +69,23 @@ describe('getFrontendFee', () => { it('>= 100 and milk in balance >= 100', () => { // arrange const sellPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: sellPrimaryAmountOver99, - buyAmount: notPrimaryTokenAmount, - milkBalance: '499', + sell: sellPrimaryAmountOver99, + buy: notPrimaryTokenAmount, + lpTokenHeld: {tokenId: 'lp.token', quantity: '499'}, sellInPrimaryTokenValue: sellPrimaryAmountOver99, buyInPrimaryTokenValue: sellPrimaryAmountOver99, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1 = 1.025 ADA }, discountTier: milkHoldersDiscountTiers[1], @@ -108,23 +95,23 @@ describe('getFrontendFee', () => { it('>= 100 and milk in balance >= 500', () => { // arrange const sellPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: sellPrimaryAmountOver99, - buyAmount: notPrimaryTokenAmount, - milkBalance: '500', + sell: sellPrimaryAmountOver99, + buy: notPrimaryTokenAmount, + lpTokenHeld: {tokenId: 'lp.token', quantity: '500'}, sellInPrimaryTokenValue: sellPrimaryAmountOver99, buyInPrimaryTokenValue: sellPrimaryAmountOver99, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1 = 1.02 ADA }, discountTier: milkHoldersDiscountTiers[0], @@ -136,23 +123,23 @@ describe('getFrontendFee', () => { it('< 100 and whatever milk in balance', () => { // arrange const buyPrimaryTokenAmount: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(99_999_999), } // act const fee = getFrontendFee({ - sellAmount: notPrimaryTokenAmount, - buyAmount: buyPrimaryTokenAmount, + sell: notPrimaryTokenAmount, + buy: buyPrimaryTokenAmount, sellInPrimaryTokenValue: buyPrimaryTokenAmount, - milkBalance: '999999999999999999', + lpTokenHeld: {tokenId: 'lp.token', quantity: '999999999999999999'}, buyInPrimaryTokenValue: buyPrimaryTokenAmount, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: Quantities.zero, }, discountTier: undefined, @@ -162,23 +149,23 @@ describe('getFrontendFee', () => { it('>= 100 and milk in balance = 0', () => { // arrange const buyPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: notPrimaryTokenAmount, - buyAmount: buyPrimaryAmountOver99, + sell: notPrimaryTokenAmount, + buy: buyPrimaryAmountOver99, sellInPrimaryTokenValue: buyPrimaryAmountOver99, - milkBalance: Quantities.zero, + lpTokenHeld: {tokenId: 'lp.token', quantity: Quantities.zero}, buyInPrimaryTokenValue: buyPrimaryAmountOver99, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA }, discountTier: milkHoldersDiscountTiers[2], @@ -188,23 +175,23 @@ describe('getFrontendFee', () => { it('>= 100 and milk in balance >= 100', () => { // arrange const buyPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: notPrimaryTokenAmount, - buyAmount: buyPrimaryAmountOver99, - milkBalance: '499', + sell: notPrimaryTokenAmount, + buy: buyPrimaryAmountOver99, + lpTokenHeld: {tokenId: 'lp.token', quantity: '499'}, sellInPrimaryTokenValue: buyPrimaryAmountOver99, buyInPrimaryTokenValue: buyPrimaryAmountOver99, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1 = 1.025 ADA }, discountTier: milkHoldersDiscountTiers[1], @@ -214,23 +201,23 @@ describe('getFrontendFee', () => { it('>= 100 and milk in balance >= 500', () => { // arrange const buyPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: notPrimaryTokenAmount, - buyAmount: buyPrimaryAmountOver99, - milkBalance: '500', + sell: notPrimaryTokenAmount, + buy: buyPrimaryAmountOver99, + lpTokenHeld: {tokenId: 'lp.token', quantity: '500'}, sellInPrimaryTokenValue: buyPrimaryAmountOver99, buyInPrimaryTokenValue: buyPrimaryAmountOver99, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1= 1.02 ADA }, discountTier: milkHoldersDiscountTiers[0], @@ -240,23 +227,23 @@ describe('getFrontendFee', () => { it('should calc 0 fee if no tier', () => { // arrange const buyPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: notPrimaryTokenAmount, - buyAmount: buyPrimaryAmountOver99, - milkBalance: '999999999999999', + sell: notPrimaryTokenAmount, + buy: buyPrimaryAmountOver99, + lpTokenHeld: {tokenId: 'lp.token', quantity: '999999999999999'}, sellInPrimaryTokenValue: buyPrimaryAmountOver99, buyInPrimaryTokenValue: buyPrimaryAmountOver99, - primaryTokenInfo, + primaryTokenId, discountTiers: [], }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: Quantities.zero, }, discountTier: undefined, @@ -266,20 +253,20 @@ describe('getFrontendFee', () => { it('should fallback - coverage only', () => { // arrange const buyPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(1_000_000), } // act const fee = getFrontendFee({ - sellAmount: notPrimaryTokenAmount, - buyAmount: buyPrimaryAmountOver99, - milkBalance: '999999999999999', - primaryTokenInfo, + sell: notPrimaryTokenAmount, + buy: buyPrimaryAmountOver99, + lpTokenHeld: {tokenId: 'lp.token', quantity: '999999999999999'}, + primaryTokenId, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: Quantities.zero, }, discountTier: undefined, @@ -295,27 +282,27 @@ describe('getFrontendFee', () => { quantity: asQuantity(99_999_999), } const sellValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(99_999_999), } const buyValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(99_999_998), } // act const fee = getFrontendFee({ - sellAmount: sellNotPrimaryAmount, - buyAmount: notPrimaryTokenAmount, + sell: sellNotPrimaryAmount, + buy: notPrimaryTokenAmount, sellInPrimaryTokenValue: sellValueInPrimaryToken, - milkBalance: '999999999999999999', + lpTokenHeld: {tokenId: 'lp.token', quantity: '999999999999999999'}, buyInPrimaryTokenValue: buyValueInPrimaryToken, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: Quantities.zero, }, discountTier: undefined, @@ -329,27 +316,27 @@ describe('getFrontendFee', () => { quantity: asQuantity(100_000_000), } const sellValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } const buyValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(99_999_998), } // act const fee = getFrontendFee({ - sellAmount: sellNotPrimaryAmountOver99, - buyAmount: notPrimaryTokenAmount, + sell: sellNotPrimaryAmountOver99, + buy: notPrimaryTokenAmount, sellInPrimaryTokenValue: sellValueInPrimaryToken, - milkBalance: Quantities.zero, + lpTokenHeld: {tokenId: 'lp.token', quantity: Quantities.zero}, buyInPrimaryTokenValue: buyValueInPrimaryToken, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_050_000), // no milk, 100 ADA * 0.05% + 1 = 1.05 ADA }, discountTier: milkHoldersDiscountTiers[2], @@ -363,27 +350,27 @@ describe('getFrontendFee', () => { quantity: asQuantity(100_000_000), } const sellValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(99_000_000), } const buyValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: sellNotPrimaryAmountOver99, - buyAmount: notPrimaryTokenAmount, - milkBalance: '499', + sell: sellNotPrimaryAmountOver99, + buy: notPrimaryTokenAmount, + lpTokenHeld: {tokenId: 'lp.token', quantity: '499'}, sellInPrimaryTokenValue: sellValueInPrimaryToken, buyInPrimaryTokenValue: buyValueInPrimaryToken, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_025_000), // hold 100-499 milk, 100 ADA * 0.025% + 1= 1.025 ADA }, discountTier: milkHoldersDiscountTiers[1], @@ -393,31 +380,31 @@ describe('getFrontendFee', () => { it('>= 100 and milk in balance >= 500 (50/50)', () => { // arrange const sellNotPrimaryAmountOver99: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } const sellValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } const buyValueInPrimaryToken: Balance.Amount = { - tokenId: primaryTokenInfo.id, + tokenId: primaryTokenId, quantity: asQuantity(100_000_000), } // act const fee = getFrontendFee({ - sellAmount: sellNotPrimaryAmountOver99, - buyAmount: notPrimaryTokenAmount, - milkBalance: '500', + sell: sellNotPrimaryAmountOver99, + buy: notPrimaryTokenAmount, + lpTokenHeld: {tokenId: 'lp.token', quantity: '500'}, sellInPrimaryTokenValue: sellValueInPrimaryToken, buyInPrimaryTokenValue: buyValueInPrimaryToken, - primaryTokenInfo, + primaryTokenId, discountTiers: milkHoldersDiscountTiers, }) // assert expect(fee).toEqual({ - frontendFee: { - tokenId: primaryTokenInfo.id, + fee: { + tokenId: primaryTokenId, quantity: asQuantity(1_020_000), // hold 500+ milk, 100 ADA * 0.020% + 1 = 1.02 ADA }, discountTier: milkHoldersDiscountTiers[0], diff --git a/packages/swap/src/helpers/orders/getFrontendFee.ts b/packages/swap/src/helpers/orders/getFrontendFee.ts index 4dd67bbd56..75ad05db88 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.ts +++ b/packages/swap/src/helpers/orders/getFrontendFee.ts @@ -8,25 +8,38 @@ import { } from '../../translators/constants' import {asQuantity} from '../../utils/asQuantity' +/** + * Calculates the frontend fee and selects a discount tier for a swap transaction. + * + * @param sell - The amount of tokens being sold. + * @param buy - The amount of tokens being bought. + * @param lpTokenHeld - The amount of LP (liquidity provider) token, is used to calc discount tier. + * @param primaryTokenId - The ID of the primary token, available in the manager. + * @param sellInPrimaryTokenValue - The value of the sell amount in terms of the primary token. + * @param buyInPrimaryTokenValue - The value of the buy amount in terms of the primary token. + * @param discountTiers - An array of discount tiers for lp token holders. Defaults to milkHoldersDiscountTiers. + * + * @returns An object containing the frontend fee and the selected discount tier. + */ export const getFrontendFee = ({ - sellAmount, - buyAmount, - milkBalance, - primaryTokenInfo, + sell, + buy, + lpTokenHeld, + primaryTokenId, sellInPrimaryTokenValue, buyInPrimaryTokenValue, discountTiers = milkHoldersDiscountTiers, }: { - sellAmount: Balance.Amount - buyAmount: Balance.Amount - milkBalance: Balance.Quantity - primaryTokenInfo: Balance.TokenInfo + sell: Balance.Amount + buy: Balance.Amount + primaryTokenId: Balance.TokenInfo['id'] + lpTokenHeld?: Balance.Amount discountTiers?: ReadonlyArray // not implemented yet (for now only ffee is added only if ADA is one of the pair) sellInPrimaryTokenValue?: Balance.Amount buyInPrimaryTokenValue?: Balance.Amount }): Readonly<{ - frontendFee: Balance.Amount + fee: Balance.Amount discountTier: SwapDiscountTier | undefined }> => { // discover trade value in ADA (sell/buy/max by pairing) @@ -36,10 +49,10 @@ export const getFrontendFee = ({ buyInPrimaryTokenValue?.quantity ?? Quantities.zero, ) let primaryTokenBiggerPairValue: Balance.Quantity - if (sellAmount.tokenId === primaryTokenInfo.id) { - primaryTokenBiggerPairValue = sellAmount.quantity - } else if (buyAmount.tokenId === primaryTokenInfo.id) { - primaryTokenBiggerPairValue = buyAmount.quantity + if (sell.tokenId === primaryTokenId) { + primaryTokenBiggerPairValue = sell.quantity + } else if (buy.tokenId === primaryTokenId) { + primaryTokenBiggerPairValue = buy.quantity } else { primaryTokenBiggerPairValue = maxPrimaryValueSellBuy } @@ -48,7 +61,7 @@ export const getFrontendFee = ({ const discountTier = discountTiers.find( (tier) => Quantities.isGreaterThanOrEqualTo( - milkBalance, + lpTokenHeld?.quantity ?? Quantities.zero, tier.secondaryTokenBalanceThreshold, ) && Quantities.isGreaterThanOrEqualTo( @@ -66,7 +79,7 @@ export const getFrontendFee = ({ ) return { - frontendFee: {tokenId: primaryTokenInfo.id, quantity: fee}, + fee: {tokenId: primaryTokenId, quantity: fee}, discountTier, } as const } diff --git a/packages/swap/src/helpers/orders/getQuantityWithSlippage.ts b/packages/swap/src/helpers/orders/getQuantityWithSlippage.ts index 145194cd52..6e50762b59 100644 --- a/packages/swap/src/helpers/orders/getQuantityWithSlippage.ts +++ b/packages/swap/src/helpers/orders/getQuantityWithSlippage.ts @@ -6,11 +6,14 @@ export const getQuantityWithSlippage = ( quantity: Balance.Quantity, slippage: number, ): Balance.Quantity => { - const q = BigInt(quantity) - const slippageAmount = ceilDivision( - BigInt(Math.floor(10000 * slippage)) * q, + const initialQuantity = BigInt(quantity) + + const slippageQuantity = ceilDivision( + BigInt(Math.floor(10000 * slippage)) * initialQuantity, BigInt(100 * 10000), ) - return asQuantity(`${q - slippageAmount}`) + const adjustedQuantity = initialQuantity - slippageQuantity + + return asQuantity(adjustedQuantity.toString()) } diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index a711db17e2..6cb307df57 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -6,17 +6,20 @@ import { import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' +import {getFrontendFee} from './getFrontendFee' export const makeOrderCalculations = ({ orderData, pools, primaryTokenId, action, + lpTokenHeld, }: Readonly<{ orderData: Swap.CreateOrderData pools: Array sellAmount: Balance.Amount buyAmount: Balance.Amount + lpTokenHeld: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] action: @@ -31,28 +34,37 @@ export const makeOrderCalculations = ({ const result: Array = [] pools.forEach((pool) => { - let orderCalculation: Writable + const buyAmountWithSlippage: Balance.Amount = { + quantity: getQuantityWithSlippage( + orderData.amounts.buy.quantity, + orderData.slippage, + ), + tokenId: orderData.amounts.buy.tokenId, + } + + const liquidityFee: Balance.Amount = getLiquidityProviderFee( + pool.fee, + orderData.amounts.sell, + ) - orderCalculation = { + const frontendFeeInfo = getFrontendFee({ + sell: orderData.amounts.sell, + buy: orderData.amounts.buy, + lpTokenHeld, + primaryTokenId: primaryTokenId, + // TODO: implement after adding the pair to ADA in the state + // sellInPrimaryTokenValue: orderData.sellInPrimaryTokenValue, + // buyInPrimaryTokenValue: orderData.buyInPrimaryTokenValue, + }) + + const orderCalculation: SwapOrderCalulation = { cost: { batcherFee: pool.batcherFee, deposit: pool.deposit, - frontendFeeInfo: { - fee: { - tokenId: primaryTokenId, - quantity: Quantities.zero, - }, - tier: undefined, - }, - liquidityFee: getLiquidityProviderFee(pool.fee, orderData.amounts.sell), - }, - buyAmountWithSlippage: { - quantity: getQuantityWithSlippage( - orderData.amounts.buy.quantity, - orderData.slippage, - ), - tokenId: orderData.amounts.buy.tokenId, + frontendFeeInfo, + liquidityFee, }, + buyAmountWithSlippage, sell: { price: '', priceDifference: '', diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index f5e1ede249..796076f8e3 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -6,7 +6,6 @@ import {getSellAmount} from '../../../helpers/orders/getSellAmount' import {getMarketPrice} from '../../../helpers/orders/getMarketPrice' import {Quantities} from '../../../utils/quantities' import {SwapDiscountTier} from '../../../translators/constants' -import _ from 'lodash' export type SwapOrderCalulation = Readonly<{ pool: Swap.Pool @@ -23,7 +22,7 @@ export type SwapOrderCalulation = Readonly<{ deposit: Balance.Amount batcherFee: Balance.Amount frontendFeeInfo: { - tier: SwapDiscountTier | undefined + discountTier: SwapDiscountTier | undefined fee: Balance.Amount } } @@ -33,11 +32,19 @@ export type SwapState = Readonly<{ createOrder: Omit & { type: Swap.OrderType marketPrice: Balance.Quantity + // TODO: is the datum in the state in use? datum: string datumHash: string + + // TODO: this will probably change after calculations - maybe the selected index? selectedPool?: Swap.Pool + // calculations: Array + // TODO: kind of metadata - slippage should be moved in here too + lpTokenHeld: Balance.Amount | undefined + sellInPrimaryTokenPrice: string + buyInPrimaryTokenPrice: string } unsignedTx: any }> @@ -53,11 +60,13 @@ export type SwapCreateOrderActions = Readonly<{ resetQuantities: () => void limitPriceChanged: (limitPrice: Balance.Quantity) => void // + // TODO: when changing quantity/token should receive & update the ADA pair along with it sellQuantityChanged: (quantity: Balance.Quantity) => void buyQuantityChanged: (quantity: Balance.Quantity) => void sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void poolPairsChanged: (pools: ReadonlyArray) => void + lpTokenHeldChanged: (amount: Balance.Amount | undefined) => void }> export enum SwapCreateOrderActionType { @@ -77,6 +86,7 @@ export enum SwapCreateOrderActionType { SellTokenIdChanged = 'sellTokenIdChanged', BuyTokenIdChanged = 'buyTokenIdChanged', PoolPairsChanged = 'poolPairsChanged', + lpTokenHeldChanged = 'lpTokenHeldChanged', } export type SwapCreateOrderAction = @@ -135,6 +145,10 @@ export type SwapCreateOrderAction = type: SwapCreateOrderActionType.PoolPairsChanged pools: ReadonlyArray } + | { + type: SwapCreateOrderActionType.lpTokenHeldChanged + amount: Balance.Amount + } export type SwapActions = Readonly<{ // TODO: import from @yoroi/common unsignedTx type @@ -193,6 +207,9 @@ export const defaultSwapState: SwapState = { selectedPool: undefined, // calculations: [], + lpTokenHeld: undefined, + sellInPrimaryTokenPrice: '', + buyInPrimaryTokenPrice: '', }, unsignedTx: undefined, } as const @@ -213,6 +230,7 @@ const defaultSwapCreateOrderActions: SwapCreateOrderActions = { sellTokenIdChanged: missingInit, buyTokenIdChanged: missingInit, poolPairsChanged: missingInit, + lpTokenHeldChanged: missingInit, } as const const defaultStateActions: SwapActions = { @@ -391,6 +409,10 @@ const createOrderReducer = ( draft.createOrder.amounts.buy.tokenId = action.tokenId break + case SwapCreateOrderActionType.lpTokenHeldChanged: + draft.createOrder.lpTokenHeld = action.amount + break + case SwapCreateOrderActionType.PoolPairsChanged: draft.createOrder.calculations = action.pools.map((pool) => { return { From 5007afbead10d9da1235ee838bc7387dea726f2a Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:11:32 +0100 Subject: [PATCH 06/67] wip: price --- .../src/helpers/orders/makeOrderCalculations.ts | 14 +++++++++++++- .../swap/src/translators/reactjs/state/state.ts | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 6cb307df57..39458eb54b 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -7,14 +7,17 @@ import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' +import { getMarketPrice } from './getMarketPrice' export const makeOrderCalculations = ({ + orderType, orderData, pools, primaryTokenId, action, lpTokenHeld, }: Readonly<{ + orderType: Swap.OrderType orderData: Swap.CreateOrderData pools: Array sellAmount: Balance.Amount @@ -34,6 +37,15 @@ export const makeOrderCalculations = ({ const result: Array = [] pools.forEach((pool) => { + let price: string = '' + const marketPrice = getMarketPrice(pool, orderData.amounts.sell) + if (orderType === 'market') { + price = marketPrice + } else { + // NOTE: while editing should never receive undefined, otherwise it will replace with market price + price = orderData.limitPrice ?? marketPrice + } + const buyAmountWithSlippage: Balance.Amount = { quantity: getQuantityWithSlippage( orderData.amounts.buy.quantity, @@ -66,7 +78,7 @@ export const makeOrderCalculations = ({ }, buyAmountWithSlippage, sell: { - price: '', + price, priceDifference: '', priceWithFees: '', priceWithFeesAndSlippage: '', diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 796076f8e3..23d459fbda 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -41,7 +41,7 @@ export type SwapState = Readonly<{ // calculations: Array - // TODO: kind of metadata - slippage should be moved in here too + // TODO: kind of metadata: - slippage, type, marketPrice should be moved in here too lpTokenHeld: Balance.Amount | undefined sellInPrimaryTokenPrice: string buyInPrimaryTokenPrice: string From 1102d7ffcde025418db7ec68a685e8f962352274 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:43:28 +0100 Subject: [PATCH 07/67] wip: sell/buy sides --- .../helpers/orders/makeOrderCalculations.ts | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 39458eb54b..095fa76c2d 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -7,7 +7,9 @@ import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' -import { getMarketPrice } from './getMarketPrice' +import {getMarketPrice} from './getMarketPrice' +import {getBuyAmount} from './getBuyAmount' +import { getSellAmount } from './getSellAmount' export const makeOrderCalculations = ({ orderType, @@ -25,6 +27,7 @@ export const makeOrderCalculations = ({ lpTokenHeld: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] + // TODO: guessing that later it will boils down to 2/3 scenarios action: | SwapCreateOrderActionType.SellQuantityChanged | SwapCreateOrderActionType.SellTokenIdChanged @@ -32,11 +35,38 @@ export const makeOrderCalculations = ({ | SwapCreateOrderActionType.BuyTokenIdChanged | SwapCreateOrderActionType.SlippageChanged | SwapCreateOrderActionType.PoolPairsChanged + | SwapCreateOrderActionType.OrderTypeChanged }>) => { - console.log(action) const result: Array = [] - pools.forEach((pool) => { + const isSellZero = Quantities.isZero(orderData.amounts.sell.quantity) + const isBuyZero = Quantities.isZero(orderData.amounts.buy.quantity) + const isLimit = orderType === 'limit' + + for (const pool of pools) { + let buy: Balance.Amount | undefined + if (action === SwapCreateOrderActionType.SellQuantityChanged) { + buy = getBuyAmount( + pool, + orderData.amounts.sell, + isLimit ? orderData.limitPrice : undefined, + ) + } + if (buy === undefined) buy = orderData.amounts.buy + + let sell: Balance.Amount | undefined + if (action === SwapCreateOrderActionType.BuyQuantityChanged) { + sell = getSellAmount( + pool, + orderData.amounts.buy, + isLimit ? orderData.limitPrice : undefined, + ) + } + if (sell === undefined) sell = orderData.amounts.sell + + console.log(buy, sell, isBuyZero, isSellZero) + + // TODO: if any side is zero set as 0 let price: string = '' const marketPrice = getMarketPrice(pool, orderData.amounts.sell) if (orderType === 'market') { @@ -90,7 +120,7 @@ export const makeOrderCalculations = ({ result.push(orderCalculation) // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? - }) + } return result } From 823f6e0aae72aaa0c232d8576748b9716536126c Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:32:36 +0100 Subject: [PATCH 08/67] wip: prices --- .../swap/src/helpers/orders/getFrontendFee.ts | 2 +- .../helpers/orders/makeOrderCalculations.ts | 55 ++++++++++++------- .../src/translators/reactjs/state/state.ts | 13 +++-- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/packages/swap/src/helpers/orders/getFrontendFee.ts b/packages/swap/src/helpers/orders/getFrontendFee.ts index 75ad05db88..8dd09d8eb1 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.ts +++ b/packages/swap/src/helpers/orders/getFrontendFee.ts @@ -74,7 +74,7 @@ export const getFrontendFee = ({ const fee = asQuantity( new BigNumber(primaryTokenBiggerPairValue) .times(discountTier?.variableFeeMultiplier ?? 0) - .integerValue(BigNumber.ROUND_UP) + .integerValue(BigNumber.ROUND_CEIL) .plus(discountTier?.fixedFee ?? 0), ) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 095fa76c2d..0edc78af1f 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -9,7 +9,7 @@ import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' -import { getSellAmount } from './getSellAmount' +import {getSellAmount} from './getSellAmount' export const makeOrderCalculations = ({ orderType, @@ -46,34 +46,48 @@ export const makeOrderCalculations = ({ for (const pool of pools) { let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { - buy = getBuyAmount( - pool, - orderData.amounts.sell, - isLimit ? orderData.limitPrice : undefined, - ) + if (isSellZero) { + buy = { + tokenId: orderData.amounts.buy.tokenId, + quantity: Quantities.zero, + } + } else { + buy = getBuyAmount( + pool, + orderData.amounts.sell, + isLimit ? orderData.limitPrice : undefined, + ) + } } if (buy === undefined) buy = orderData.amounts.buy let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - sell = getSellAmount( - pool, - orderData.amounts.buy, - isLimit ? orderData.limitPrice : undefined, - ) + if (isBuyZero) { + sell = { + tokenId: orderData.amounts.sell.tokenId, + quantity: Quantities.zero, + } + } else { + sell = getSellAmount( + pool, + orderData.amounts.buy, + isLimit ? orderData.limitPrice : undefined, + ) + } } if (sell === undefined) sell = orderData.amounts.sell console.log(buy, sell, isBuyZero, isSellZero) // TODO: if any side is zero set as 0 - let price: string = '' + let priceBase: string = '' const marketPrice = getMarketPrice(pool, orderData.amounts.sell) if (orderType === 'market') { - price = marketPrice + priceBase = marketPrice } else { // NOTE: while editing should never receive undefined, otherwise it will replace with market price - price = orderData.limitPrice ?? marketPrice + priceBase = orderData.limitPrice ?? marketPrice } const buyAmountWithSlippage: Balance.Amount = { @@ -107,12 +121,13 @@ export const makeOrderCalculations = ({ liquidityFee, }, buyAmountWithSlippage, - sell: { - price, - priceDifference: '', - priceWithFees: '', - priceWithFeesAndSlippage: '', - priceWithSlippage: '', + prices: { + base: priceBase, + market: marketPrice, + withFees: '', + difference: '', + withSlippage: '', + withFeesAndSlippage: '', }, pool, } diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 23d459fbda..d3e44ec8ed 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -9,12 +9,13 @@ import {SwapDiscountTier} from '../../../translators/constants' export type SwapOrderCalulation = Readonly<{ pool: Swap.Pool - sell: { - price: string - priceWithFees: string - priceDifference: string - priceWithSlippage: string - priceWithFeesAndSlippage: string + prices: { + base: string + market: string + withFees: string + difference: string + withSlippage: string + withFeesAndSlippage: string } buyAmountWithSlippage: Balance.Amount cost: { From a5096a79300aaae45e3ca68223e8c4c7c3a05d07 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:27:30 +0100 Subject: [PATCH 09/67] wip: prices --- .../helpers/orders/makeOrderCalculations.ts | 29 ++++++++++++++----- .../src/translators/reactjs/state/state.ts | 13 ++++++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 0edc78af1f..f61a883f73 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -14,6 +14,7 @@ import {getSellAmount} from './getSellAmount' export const makeOrderCalculations = ({ orderType, orderData, + ptPrices, pools, primaryTokenId, action, @@ -21,6 +22,10 @@ export const makeOrderCalculations = ({ }: Readonly<{ orderType: Swap.OrderType orderData: Swap.CreateOrderData + ptPrices: { + buy: string + sell: string + } pools: Array sellAmount: Balance.Amount buyAmount: Balance.Amount @@ -44,6 +49,7 @@ export const makeOrderCalculations = ({ const isLimit = orderType === 'limit' for (const pool of pools) { + // when changing sell quantity, calculate buy quantity let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { if (isSellZero) { @@ -61,6 +67,7 @@ export const makeOrderCalculations = ({ } if (buy === undefined) buy = orderData.amounts.buy + // when changing buy quantity, calculate sell quantity let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { if (isBuyZero) { @@ -78,18 +85,22 @@ export const makeOrderCalculations = ({ } if (sell === undefined) sell = orderData.amounts.sell - console.log(buy, sell, isBuyZero, isSellZero) + // when changing sell token ? + // when changing buy token ? + // when changing pool - limit order ? + // when changing price - limit order ? - // TODO: if any side is zero set as 0 - let priceBase: string = '' + // recalculate price base, limit is user's input, market from pool + let priceBase: string const marketPrice = getMarketPrice(pool, orderData.amounts.sell) if (orderType === 'market') { priceBase = marketPrice } else { - // NOTE: while editing should never receive undefined, otherwise it will replace with market price + // NOTE: while editing should never receive undefined or '', undefined = market price, '' = NaN priceBase = orderData.limitPrice ?? marketPrice } + // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { quantity: getQuantityWithSlippage( orderData.amounts.buy.quantity, @@ -98,11 +109,13 @@ export const makeOrderCalculations = ({ tokenId: orderData.amounts.buy.tokenId, } + // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee( pool.fee, orderData.amounts.sell, ) + // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ sell: orderData.amounts.sell, buy: orderData.amounts.buy, @@ -124,10 +137,10 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: '', - difference: '', - withSlippage: '', - withFeesAndSlippage: '', + withFees: '0', + difference: '0', + withSlippage: '0', + withFeesAndSlippage: '0', }, pool, } diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index d3e44ec8ed..9c4146d29d 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -44,8 +44,11 @@ export type SwapState = Readonly<{ calculations: Array // TODO: kind of metadata: - slippage, type, marketPrice should be moved in here too lpTokenHeld: Balance.Amount | undefined - sellInPrimaryTokenPrice: string - buyInPrimaryTokenPrice: string + // primary token price in terms of sell/buy token + ptPrices: { + sell: string + buy: string + } } unsignedTx: any }> @@ -209,8 +212,10 @@ export const defaultSwapState: SwapState = { // calculations: [], lpTokenHeld: undefined, - sellInPrimaryTokenPrice: '', - buyInPrimaryTokenPrice: '', + ptPrices: { + sell: '0', + buy: '0', + }, }, unsignedTx: undefined, } as const From bb3d77b224e44641c1b09a080800c03ec4847afb Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:32:48 +0100 Subject: [PATCH 10/67] wip: helpers dealt with 0 --- .../helpers/orders/makeOrderCalculations.ts | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index f61a883f73..49922f6f61 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -44,44 +44,28 @@ export const makeOrderCalculations = ({ }>) => { const result: Array = [] - const isSellZero = Quantities.isZero(orderData.amounts.sell.quantity) - const isBuyZero = Quantities.isZero(orderData.amounts.buy.quantity) const isLimit = orderType === 'limit' for (const pool of pools) { - // when changing sell quantity, calculate buy quantity + // when changing sell quantity, calculate buy quantity based on order type let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { - if (isSellZero) { - buy = { - tokenId: orderData.amounts.buy.tokenId, - quantity: Quantities.zero, - } - } else { - buy = getBuyAmount( - pool, - orderData.amounts.sell, - isLimit ? orderData.limitPrice : undefined, - ) - } + buy = getBuyAmount( + pool, + orderData.amounts.sell, + isLimit ? orderData.limitPrice : undefined, + ) } if (buy === undefined) buy = orderData.amounts.buy - // when changing buy quantity, calculate sell quantity + // when changing buy quantity, calculate sell quantity based on order type let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - if (isBuyZero) { - sell = { - tokenId: orderData.amounts.sell.tokenId, - quantity: Quantities.zero, - } - } else { - sell = getSellAmount( - pool, - orderData.amounts.buy, - isLimit ? orderData.limitPrice : undefined, - ) - } + sell = getSellAmount( + pool, + orderData.amounts.buy, + isLimit ? orderData.limitPrice : undefined, + ) } if (sell === undefined) sell = orderData.amounts.sell From c744df521ad8394a1b78d5767228eb5200129d61 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:40:13 +0100 Subject: [PATCH 11/67] wip: price with fees --- .../helpers/orders/makeOrderCalculations.ts | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 49922f6f61..cc4d96f330 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,4 +1,5 @@ import {Balance, Swap, Writable} from '@yoroi/types' +import {BigNumber} from 'bignumber.js' import { SwapCreateOrderActionType, SwapOrderCalulation, @@ -10,6 +11,7 @@ import {getFrontendFee} from './getFrontendFee' import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' import {getSellAmount} from './getSellAmount' +import {asQuantity} from '../../utils/asQuantity' export const makeOrderCalculations = ({ orderType, @@ -105,11 +107,41 @@ export const makeOrderCalculations = ({ buy: orderData.amounts.buy, lpTokenHeld, primaryTokenId: primaryTokenId, - // TODO: implement after adding the pair to ADA in the state - // sellInPrimaryTokenValue: orderData.sellInPrimaryTokenValue, - // buyInPrimaryTokenValue: orderData.buyInPrimaryTokenValue, + sellInPrimaryTokenValue: { + tokenId: primaryTokenId, + quantity: asQuantity( + new BigNumber(orderData.amounts.sell.quantity) + .times(ptPrices.sell) + .integerValue(BigNumber.ROUND_CEIL), + ), + }, + buyInPrimaryTokenValue: { + tokenId: primaryTokenId, + quantity: asQuantity( + new BigNumber(orderData.amounts.buy.quantity) + .times(ptPrices.buy) + .integerValue(BigNumber.ROUND_CEIL), + ), + }, }) + // transform fees in terms of sell side quantity * pt price (unit of fees) + const feeInSellSideQuantities = { + batcherFee: new BigNumber(pool.batcherFee.quantity) + .times(ptPrices.sell) + .integerValue(BigNumber.ROUND_CEIL), + frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) + .times(ptPrices.sell) + .integerValue(BigNumber.ROUND_CEIL), + } + + // add up all that's being sold in sell terms + const priceWithFees = new BigNumber(sell.quantity) + .plus(feeInSellSideQuantities.batcherFee) + .plus(feeInSellSideQuantities.frontendFee) + .dividedBy(new BigNumber(buy.quantity)) + .toString() + const orderCalculation: SwapOrderCalulation = { cost: { batcherFee: pool.batcherFee, @@ -121,7 +153,8 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: '0', + withFees: priceWithFees, + // TODO: add later difference: '0', withSlippage: '0', withFeesAndSlippage: '0', From f2369cd86cf167a8ad42cf859343f136c96be9a3 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:29:03 +0100 Subject: [PATCH 12/67] wip: price difference --- .../helpers/orders/makeOrderCalculations.ts | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index cc4d96f330..6b5a9da46b 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -43,6 +43,8 @@ export const makeOrderCalculations = ({ | SwapCreateOrderActionType.SlippageChanged | SwapCreateOrderActionType.PoolPairsChanged | SwapCreateOrderActionType.OrderTypeChanged + | SwapCreateOrderActionType.SwitchTokens + | SwapCreateOrderActionType.LimitPriceChanged }>) => { const result: Array = [] @@ -126,6 +128,7 @@ export const makeOrderCalculations = ({ }) // transform fees in terms of sell side quantity * pt price (unit of fees) + // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) .times(ptPrices.sell) @@ -136,10 +139,25 @@ export const makeOrderCalculations = ({ } // add up all that's being sold in sell terms - const priceWithFees = new BigNumber(sell.quantity) + const sellWithFees = new BigNumber(sell.quantity) .plus(feeInSellSideQuantities.batcherFee) .plus(feeInSellSideQuantities.frontendFee) - .dividedBy(new BigNumber(buy.quantity)) + + const priceWithFees = sellWithFees.dividedBy(buy.quantity) + + const priceWithSlippage = new BigNumber(sell.quantity) + .dividedBy(buyAmountWithSlippage.quantity) + .toString() + + const priceWithFeesAndSlippage = sellWithFees + .dividedBy(buyAmountWithSlippage.quantity) + .toString() + + // always based, if is limit it can lead to a weird percentage + const priceDifference = priceWithFees + .minus(priceBase) + .dividedBy(priceBase) + .times(100) .toString() const orderCalculation: SwapOrderCalulation = { @@ -153,11 +171,10 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: priceWithFees, - // TODO: add later - difference: '0', - withSlippage: '0', - withFeesAndSlippage: '0', + withFees: priceWithFees.toString(), + withSlippage: priceWithSlippage, + withFeesAndSlippage: priceWithFeesAndSlippage, + difference: priceDifference, }, pool, } From 98aab072816f02101cc5f7bfbd005ce0f411c3cc Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 16:37:07 +0100 Subject: [PATCH 13/67] wip: state --- .../helpers/orders/makeOrderCalculations.ts | 89 +++++++------- .../src/translators/reactjs/state/state.ts | 109 +++++++++++------- 2 files changed, 108 insertions(+), 90 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 6b5a9da46b..d2a2eed026 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,11 +1,10 @@ -import {Balance, Swap, Writable} from '@yoroi/types' +import {Balance, Swap} from '@yoroi/types' import {BigNumber} from 'bignumber.js' import { SwapCreateOrderActionType, SwapOrderCalulation, } from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' -import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' import {getMarketPrice} from './getMarketPrice' @@ -15,113 +14,111 @@ import {asQuantity} from '../../utils/asQuantity' export const makeOrderCalculations = ({ orderType, - orderData, + amounts, + limitPrice, + slippage, ptPrices, pools, primaryTokenId, - action, lpTokenHeld, + action, }: Readonly<{ orderType: Swap.OrderType - orderData: Swap.CreateOrderData + amounts: { + sell: Balance.Amount + buy: Balance.Amount + } + limitPrice: `${number}` | undefined ptPrices: { - buy: string - sell: string + buy: `${number}` | undefined + sell: `${number}` | undefined } - pools: Array - sellAmount: Balance.Amount - buyAmount: Balance.Amount - lpTokenHeld: Balance.Amount + pools: ReadonlyArray + lpTokenHeld: Balance.Amount | undefined slippage: number primaryTokenId: Balance.TokenInfo['id'] // TODO: guessing that later it will boils down to 2/3 scenarios action: | SwapCreateOrderActionType.SellQuantityChanged - | SwapCreateOrderActionType.SellTokenIdChanged | SwapCreateOrderActionType.BuyQuantityChanged + // same bag for now + | SwapCreateOrderActionType.SellTokenIdChanged | SwapCreateOrderActionType.BuyTokenIdChanged | SwapCreateOrderActionType.SlippageChanged | SwapCreateOrderActionType.PoolPairsChanged | SwapCreateOrderActionType.OrderTypeChanged | SwapCreateOrderActionType.SwitchTokens | SwapCreateOrderActionType.LimitPriceChanged + | SwapCreateOrderActionType.ResetQuantities + | SwapCreateOrderActionType.LpTokenHeldChanged }>) => { const result: Array = [] - const isLimit = orderType === 'limit' + // when changing sell token ? + // when changing buy token ? + // when changing pool - limit order ? + // when changing price - limit order ? + // when switching sell/buy + // when changing slippage + for (const pool of pools) { // when changing sell quantity, calculate buy quantity based on order type let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { - buy = getBuyAmount( - pool, - orderData.amounts.sell, - isLimit ? orderData.limitPrice : undefined, - ) + buy = getBuyAmount(pool, amounts.sell, isLimit ? limitPrice : undefined) } - if (buy === undefined) buy = orderData.amounts.buy + if (buy === undefined) buy = amounts.buy // when changing buy quantity, calculate sell quantity based on order type let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - sell = getSellAmount( - pool, - orderData.amounts.buy, - isLimit ? orderData.limitPrice : undefined, - ) + sell = getSellAmount(pool, amounts.buy, isLimit ? limitPrice : undefined) } - if (sell === undefined) sell = orderData.amounts.sell - - // when changing sell token ? - // when changing buy token ? - // when changing pool - limit order ? - // when changing price - limit order ? + if (sell === undefined) sell = amounts.sell // recalculate price base, limit is user's input, market from pool let priceBase: string - const marketPrice = getMarketPrice(pool, orderData.amounts.sell) + const marketPrice = getMarketPrice(pool, amounts.sell) if (orderType === 'market') { priceBase = marketPrice } else { // NOTE: while editing should never receive undefined or '', undefined = market price, '' = NaN - priceBase = orderData.limitPrice ?? marketPrice + // when switching sell/buy limit is kept + priceBase = limitPrice ?? marketPrice } // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { - quantity: getQuantityWithSlippage( - orderData.amounts.buy.quantity, - orderData.slippage, - ), - tokenId: orderData.amounts.buy.tokenId, + quantity: getQuantityWithSlippage(amounts.buy.quantity, slippage), + tokenId: amounts.buy.tokenId, } // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee( pool.fee, - orderData.amounts.sell, + amounts.sell, ) // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ - sell: orderData.amounts.sell, - buy: orderData.amounts.buy, + sell: amounts.sell, + buy: amounts.buy, lpTokenHeld, primaryTokenId: primaryTokenId, sellInPrimaryTokenValue: { tokenId: primaryTokenId, quantity: asQuantity( - new BigNumber(orderData.amounts.sell.quantity) - .times(ptPrices.sell) + new BigNumber(amounts.sell.quantity) + .times(ptPrices.sell ?? 0) .integerValue(BigNumber.ROUND_CEIL), ), }, buyInPrimaryTokenValue: { tokenId: primaryTokenId, quantity: asQuantity( - new BigNumber(orderData.amounts.buy.quantity) - .times(ptPrices.buy) + new BigNumber(amounts.buy.quantity) + .times(ptPrices.buy ?? 0) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -131,10 +128,10 @@ export const makeOrderCalculations = ({ // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) - .times(ptPrices.sell) + .times(ptPrices.sell ?? 0) .integerValue(BigNumber.ROUND_CEIL), frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .times(ptPrices.sell) + .times(ptPrices.sell ?? 0) .integerValue(BigNumber.ROUND_CEIL), } diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 9c4146d29d..db5efe6704 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -6,6 +6,7 @@ import {getSellAmount} from '../../../helpers/orders/getSellAmount' import {getMarketPrice} from '../../../helpers/orders/getMarketPrice' import {Quantities} from '../../../utils/quantities' import {SwapDiscountTier} from '../../../translators/constants' +import {makeOrderCalculations} from 'helpers/orders/makeOrderCalculations' export type SwapOrderCalulation = Readonly<{ pool: Swap.Pool @@ -46,9 +47,10 @@ export type SwapState = Readonly<{ lpTokenHeld: Balance.Amount | undefined // primary token price in terms of sell/buy token ptPrices: { - sell: string - buy: string + sell: `${number}` | undefined + buy: `${number}` | undefined } + pools: Array } unsignedTx: any }> @@ -90,7 +92,7 @@ export enum SwapCreateOrderActionType { SellTokenIdChanged = 'sellTokenIdChanged', BuyTokenIdChanged = 'buyTokenIdChanged', PoolPairsChanged = 'poolPairsChanged', - lpTokenHeldChanged = 'lpTokenHeldChanged', + LpTokenHeldChanged = 'lpTokenHeldChanged', } export type SwapCreateOrderAction = @@ -150,8 +152,8 @@ export type SwapCreateOrderAction = pools: ReadonlyArray } | { - type: SwapCreateOrderActionType.lpTokenHeldChanged - amount: Balance.Amount + type: SwapCreateOrderActionType.LpTokenHeldChanged + amount: Balance.Amount | undefined } export type SwapActions = Readonly<{ @@ -216,6 +218,7 @@ export const defaultSwapState: SwapState = { sell: '0', buy: '0', }, + pools: [], }, unsignedTx: undefined, } as const @@ -401,62 +404,80 @@ const createOrderReducer = ( // case SwapCreateOrderActionType.SellQuantityChanged: draft.createOrder.amounts.sell.quantity = action.quantity + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: draft.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: SwapCreateOrderActionType.PoolPairsChanged, + }) + // TODO: use getBest pool filter break case SwapCreateOrderActionType.BuyQuantityChanged: draft.createOrder.amounts.buy.quantity = action.quantity break + // TODO: this should have the pools list too case SwapCreateOrderActionType.SellTokenIdChanged: draft.createOrder.amounts.sell.tokenId = action.tokenId + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: draft.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: SwapCreateOrderActionType.PoolPairsChanged, + }) + // TODO: use getBest pool filter break + // TODO: this should have the pools list too case SwapCreateOrderActionType.BuyTokenIdChanged: draft.createOrder.amounts.buy.tokenId = action.tokenId break - case SwapCreateOrderActionType.lpTokenHeldChanged: + case SwapCreateOrderActionType.LpTokenHeldChanged: draft.createOrder.lpTokenHeld = action.amount + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: state.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: action.amount, + action: SwapCreateOrderActionType.PoolPairsChanged, + }) + // TODO: use getBest pool filter break case SwapCreateOrderActionType.PoolPairsChanged: - draft.createOrder.calculations = action.pools.map((pool) => { - return { - buyAmountWithSlippage: { - quantity: Quantities.zero, - tokenId: state.createOrder.amounts.buy.tokenId, - }, - sell: { - price: '', - priceDifference: '', - priceWithFees: '', - priceWithFeesAndSlippage: '', - priceWithSlippage: '', - }, - cost: { - batcherFee: { - quantity: Quantities.zero, - tokenId: state.createOrder.amounts.buy.tokenId, - }, - deposit: { - quantity: Quantities.zero, - tokenId: state.createOrder.amounts.buy.tokenId, - }, - liquidityFee: { - quantity: Quantities.zero, - tokenId: state.createOrder.amounts.buy.tokenId, - }, - frontendFeeInfo: { - tier: undefined, - fee: { - quantity: Quantities.zero, - tokenId: state.createOrder.amounts.buy.tokenId, - }, - }, - }, - pool, - } + const pools = [...action.pools] + draft.createOrder.pools = pools + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: state.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: SwapCreateOrderActionType.PoolPairsChanged, }) + // TODO: use getBest pool filter break } }) @@ -469,8 +490,8 @@ const swapReducer = (state: SwapState, action: SwapAction) => { draft.unsignedTx = action.unsignedTx break case SwapActionType.ResetState: - draft.createOrder = defaultSwapState.createOrder - draft.unsignedTx = defaultSwapState.unsignedTx + draft.createOrder = {...defaultSwapState.createOrder} + draft.unsignedTx = {...defaultSwapState.unsignedTx} break } }) From 973e546188386091cf741f6799367eeafee4265b Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 17:01:14 +0100 Subject: [PATCH 14/67] wip: state --- .../src/translators/reactjs/state/state.ts | 78 ++++++++++++++++++- 1 file changed, 74 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index db5efe6704..db5807867a 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -261,6 +261,19 @@ const createOrderReducer = ( case SwapCreateOrderActionType.OrderTypeChanged: draft.createOrder.type = action.orderType + draft.createOrder.calculations = makeOrderCalculations({ + orderType: action.orderType, + amounts: state.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: action.type, + }) + // TODO: use getBest pool filter, upd state accordingly + if (state.createOrder.selectedPool === undefined) break draft.createOrder.amounts.buy = getBuyAmount( @@ -310,6 +323,9 @@ const createOrderReducer = ( case SwapCreateOrderActionType.SelectedPoolChanged: draft.createOrder.selectedPool = action.pool + + // TODO: just get the calculations.find() and update the state after + if (action.pool === undefined) { draft.createOrder.marketPrice = Quantities.zero draft.createOrder.limitPrice = Quantities.zero @@ -331,6 +347,19 @@ const createOrderReducer = ( case SwapCreateOrderActionType.SlippageChanged: draft.createOrder.slippage = action.slippage + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: state.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: action.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: action.type, + }) + // TODO: use getBest pool filter break case SwapCreateOrderActionType.TxPayloadChanged: @@ -345,6 +374,19 @@ const createOrderReducer = ( buy: state.createOrder.amounts.sell, } + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: draft.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: action.type, + }) + // TODO: use getBest pool filter, upd state accordingly + if (state.createOrder.selectedPool === undefined) break draft.createOrder.marketPrice = getMarketPrice( @@ -386,6 +428,21 @@ const createOrderReducer = ( tokenId: state.createOrder.amounts.buy.tokenId, }, } + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: draft.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: action.type, + }) + // TODO: use getBest pool filter + + // TODO: this should be based on the best pool selection draft.createOrder.limitPrice = state.createOrder.marketPrice break @@ -399,6 +456,19 @@ const createOrderReducer = ( state.createOrder.amounts.sell, action.limitPrice, ) + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: state.createOrder.amounts, + limitPrice: action.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: action.type, + }) + // TODO: use getBest pool filter break // @@ -414,7 +484,7 @@ const createOrderReducer = ( pools: state.createOrder.pools, primaryTokenId: '', lpTokenHeld: state.createOrder.lpTokenHeld, - action: SwapCreateOrderActionType.PoolPairsChanged, + action: action.type, }) // TODO: use getBest pool filter break @@ -436,7 +506,7 @@ const createOrderReducer = ( pools: state.createOrder.pools, primaryTokenId: '', lpTokenHeld: state.createOrder.lpTokenHeld, - action: SwapCreateOrderActionType.PoolPairsChanged, + action: action.type, }) // TODO: use getBest pool filter break @@ -458,7 +528,7 @@ const createOrderReducer = ( pools: state.createOrder.pools, primaryTokenId: '', lpTokenHeld: action.amount, - action: SwapCreateOrderActionType.PoolPairsChanged, + action: action.type, }) // TODO: use getBest pool filter break @@ -475,7 +545,7 @@ const createOrderReducer = ( pools: pools, primaryTokenId: '', lpTokenHeld: state.createOrder.lpTokenHeld, - action: SwapCreateOrderActionType.PoolPairsChanged, + action: action.type, }) // TODO: use getBest pool filter break From 3ecdb3aad8910905f80fe97ace735839c866bfc8 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 17:58:10 +0100 Subject: [PATCH 15/67] wip: state --- .../helpers/orders/makeOrderCalculations.ts | 4 ++-- .../reactjs/provider/SwapProvider.tsx | 19 +++++++++++++++++++ .../translators/reactjs/state/state.mocks.ts | 7 +++++++ .../src/translators/reactjs/state/state.ts | 18 +++++++++++------- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index d2a2eed026..6936186627 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -62,7 +62,7 @@ export const makeOrderCalculations = ({ // when switching sell/buy // when changing slippage - for (const pool of pools) { + pools.forEach((pool) => { // when changing sell quantity, calculate buy quantity based on order type let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { @@ -179,7 +179,7 @@ export const makeOrderCalculations = ({ result.push(orderCalculation) // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? - } + }) return result } diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx index 268d5c7edf..c58666fe13 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx @@ -78,6 +78,25 @@ export const SwapProvider = ({ limitPriceChanged: (limitPrice: Balance.Quantity) => { dispatch({type: SwapCreateOrderActionType.LimitPriceChanged, limitPrice}) }, + // + buyQuantityChanged: (quantity: Balance.Quantity) => { + dispatch({type: SwapCreateOrderActionType.BuyQuantityChanged, quantity}) + }, + sellQuantityChanged: (quantity: Balance.Quantity) => { + dispatch({type: SwapCreateOrderActionType.SellQuantityChanged, quantity}) + }, + lpTokenHeldChanged: (amount: Balance.Amount | undefined) => { + dispatch({type: SwapCreateOrderActionType.LpTokenHeldChanged, amount}) + }, + buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { + dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, tokenId}) + }, + sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { + dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, tokenId}) + }, + poolPairsChanged: (pools: ReadonlyArray) => { + dispatch({type: SwapCreateOrderActionType.PoolPairsChanged, pools}) + }, }).current const context = React.useMemo( diff --git a/packages/swap/src/translators/reactjs/state/state.mocks.ts b/packages/swap/src/translators/reactjs/state/state.mocks.ts index 9c8748a40c..9801f5b166 100644 --- a/packages/swap/src/translators/reactjs/state/state.mocks.ts +++ b/packages/swap/src/translators/reactjs/state/state.mocks.ts @@ -31,6 +31,13 @@ export const mockSwapStateDefault: SwapState = { lastUpdate: '', lpToken: {tokenId: '', quantity: '0'}, }, + calculations: [], + lpTokenHeld: undefined, + pools: [], + ptPrices: { + sell: '0', + buy: '0', + }, }, unsignedTx: undefined, } as const diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index db5807867a..ed6556b5ba 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -6,7 +6,7 @@ import {getSellAmount} from '../../../helpers/orders/getSellAmount' import {getMarketPrice} from '../../../helpers/orders/getMarketPrice' import {Quantities} from '../../../utils/quantities' import {SwapDiscountTier} from '../../../translators/constants' -import {makeOrderCalculations} from 'helpers/orders/makeOrderCalculations' +import {makeOrderCalculations} from '../../../helpers/orders/makeOrderCalculations' export type SwapOrderCalulation = Readonly<{ pool: Swap.Pool @@ -42,7 +42,7 @@ export type SwapState = Readonly<{ selectedPool?: Swap.Pool // - calculations: Array + calculations: ReadonlyArray // TODO: kind of metadata: - slippage, type, marketPrice should be moved in here too lpTokenHeld: Balance.Amount | undefined // primary token price in terms of sell/buy token @@ -50,7 +50,7 @@ export type SwapState = Readonly<{ sell: `${number}` | undefined buy: `${number}` | undefined } - pools: Array + pools: ReadonlyArray } unsignedTx: any }> @@ -212,13 +212,13 @@ export const defaultSwapState: SwapState = { marketPrice: Quantities.zero, selectedPool: undefined, // - calculations: [], + calculations: [] as const, lpTokenHeld: undefined, ptPrices: { sell: '0', buy: '0', }, - pools: [], + pools: [] as const, }, unsignedTx: undefined, } as const @@ -560,8 +560,12 @@ const swapReducer = (state: SwapState, action: SwapAction) => { draft.unsignedTx = action.unsignedTx break case SwapActionType.ResetState: - draft.createOrder = {...defaultSwapState.createOrder} - draft.unsignedTx = {...defaultSwapState.unsignedTx} + draft.createOrder = { + ...defaultSwapState.createOrder, + calculations: [...defaultSwapState.createOrder.calculations], + pools: [...defaultSwapState.createOrder.pools], + } + draft.unsignedTx = defaultSwapState.unsignedTx break } }) From f9f824e8ca5e5ca12223cfb59507b6c6ac6c6ff9 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 19:51:57 +0100 Subject: [PATCH 16/67] wip: tests --- .../reactjs/provider/SwapProvider.test.tsx | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx index 57aa64942a..4aa3dd2e0d 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx @@ -4,7 +4,7 @@ import {renderHook, act} from '@testing-library/react-hooks' import {SwapProvider} from './SwapProvider' import {mockSwapManager, swapManagerMocks} from '../../../manager.mocks' -import {defaultSwapState} from '../state/state' +import {SwapState, defaultSwapState} from '../state/state' import {queryClientFixture} from '../../../fixtures/query-client' import {useSwap} from '../hooks/useSwap' @@ -189,8 +189,9 @@ describe('SwapProvider', () => { }) it('SwitchTokens market', () => { - const initialState: any = { + const initialState: SwapState = { createOrder: { + ...defaultSwapState.createOrder, amounts: { sell: { quantity: '10', @@ -214,6 +215,7 @@ describe('SwapProvider', () => { tokenB: {tokenId: 'policyId.buy', quantity: '100'}, }, }, + unsignedTx: undefined, } const wrapper = ({children}: any) => ( @@ -244,10 +246,11 @@ describe('SwapProvider', () => { }) it('SwitchTokens limit', () => { - const initialState: any = { + const initialState: SwapState = { createOrder: { + ...defaultSwapState.createOrder, type: 'limit', - limitPrice: 2, + limitPrice: '2', amounts: { sell: { quantity: '10', @@ -271,6 +274,7 @@ describe('SwapProvider', () => { tokenB: {tokenId: 'policyId.buy', quantity: '100'}, }, }, + unsignedTx: undefined, } const wrapper = ({children}: any) => ( @@ -316,8 +320,9 @@ describe('SwapProvider', () => { }) it('ResetQuantities', () => { - const initiState: any = { + const initiState: SwapState = { createOrder: { + ...defaultSwapState.createOrder, amounts: { sell: { quantity: '1', @@ -343,6 +348,7 @@ describe('SwapProvider', () => { limitPrice: '3', marketPrice: '1', }, + unsignedTx: undefined, } const wrapper = ({children}: any) => ( @@ -374,8 +380,9 @@ describe('SwapProvider', () => { }) it('ResetState', () => { - const initialState: any = { + const initialState: SwapState = { createOrder: { + ...defaultSwapState.createOrder, amounts: { sell: { quantity: '1', @@ -387,6 +394,7 @@ describe('SwapProvider', () => { }, }, }, + unsignedTx: undefined, } const wrapper = ({children}: any) => ( From 002c41d627fa997264e2d64f272089c1838c38ec Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 21:55:27 +0100 Subject: [PATCH 17/67] wip: state --- .../helpers/orders/makeOrderCalculations.ts | 2 ++ .../src/translators/reactjs/state/state.ts | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 6936186627..f4aacbb670 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -61,6 +61,8 @@ export const makeOrderCalculations = ({ // when changing price - limit order ? // when switching sell/buy // when changing slippage + // when changing the lp token held + // when reseting quantities pools.forEach((pool) => { // when changing sell quantity, calculate buy quantity based on order type diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index ed6556b5ba..f3c2297990 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -491,6 +491,19 @@ const createOrderReducer = ( case SwapCreateOrderActionType.BuyQuantityChanged: draft.createOrder.amounts.buy.quantity = action.quantity + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: draft.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: action.type, + }) + // TODO: use getBest pool filter break // TODO: this should have the pools list too @@ -514,6 +527,19 @@ const createOrderReducer = ( // TODO: this should have the pools list too case SwapCreateOrderActionType.BuyTokenIdChanged: draft.createOrder.amounts.buy.tokenId = action.tokenId + + draft.createOrder.calculations = makeOrderCalculations({ + orderType: state.createOrder.type, + amounts: draft.createOrder.amounts, + limitPrice: state.createOrder.limitPrice, + slippage: state.createOrder.slippage, + ptPrices: state.createOrder.ptPrices, + pools: state.createOrder.pools, + primaryTokenId: '', + lpTokenHeld: state.createOrder.lpTokenHeld, + action: action.type, + }) + // TODO: use getBest pool filter break case SwapCreateOrderActionType.LpTokenHeldChanged: From f89887bf3152eaaf97091725ee7f124b7be5a6c3 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 22:59:06 +0100 Subject: [PATCH 18/67] wip: added getPrice --- packages/openswap/src/api.ts | 15 +++ packages/openswap/src/config.ts | 2 + packages/openswap/src/index.ts | 3 + packages/openswap/src/price.spec.ts | 98 +++++++++++++++++++ packages/openswap/src/price.ts | 30 ++++++ packages/openswap/src/types.ts | 42 ++++++++ .../src/adapters/openswap-api/api.test.ts | 29 ++++++ .../swap/src/adapters/openswap-api/api.ts | 17 ++++ .../adapters/openswap-api/openswap.mocks.ts | 48 +++++++++ .../swap/src/helpers/transformers.test.ts | 19 ++++ packages/swap/src/helpers/transformers.ts | 10 ++ packages/swap/src/manager.mocks.ts | 17 ++++ packages/swap/src/manager.test.ts | 1 + packages/swap/src/manager.ts | 6 ++ packages/types/src/swap/api.ts | 4 + packages/types/src/swap/manager.ts | 3 + 16 files changed, 344 insertions(+) create mode 100644 packages/openswap/src/price.spec.ts create mode 100644 packages/openswap/src/price.ts diff --git a/packages/openswap/src/api.ts b/packages/openswap/src/api.ts index 80a2d9eb60..f572631f18 100644 --- a/packages/openswap/src/api.ts +++ b/packages/openswap/src/api.ts @@ -11,9 +11,11 @@ import { CancelOrderRequest, CreateOrderRequest, Network, + PriceAddress, TokenAddress, } from './types' import {axiosClient} from './config' +import {getPrice} from './price' export class OpenSwapApi { constructor( @@ -51,6 +53,19 @@ export class OpenSwapApi { ) } + public async getPrice({ + baseToken, + quoteToken, + }: { + baseToken: PriceAddress + quoteToken: PriceAddress + }) { + return getPrice( + {network: this.network, client: this.client}, + {baseToken, quoteToken}, + ) + } + public async getPools({ tokenA, tokenB, diff --git a/packages/openswap/src/config.ts b/packages/openswap/src/config.ts index 67ec4d65e8..2c7f9cb383 100644 --- a/packages/openswap/src/config.ts +++ b/packages/openswap/src/config.ts @@ -2,6 +2,7 @@ import axios from 'axios' export const SWAP_API_ENDPOINTS = { mainnet: { + getPrice: 'https://api.muesliswap.com/price', getPools: 'https://onchain2.muesliswap.com/pools/pair', getOrders: 'https://onchain2.muesliswap.com/orders/all/', getCompletedOrders: 'https://api.muesliswap.com/orders/v2', @@ -11,6 +12,7 @@ export const SWAP_API_ENDPOINTS = { 'https://aggregator.muesliswap.com/cancelSwapTransaction', }, preprod: { + getPrice: 'https://preprod.api.muesliswap.com/price', getPools: 'https://preprod.pools.muesliswap.com/pools/pair', getOrders: 'https://preprod.pools.muesliswap.com/orders/all/', getCompletedOrders: 'https://api.muesliswap.com/orders/v2', diff --git a/packages/openswap/src/index.ts b/packages/openswap/src/index.ts index 5ff63bff32..b07e0b7057 100644 --- a/packages/openswap/src/index.ts +++ b/packages/openswap/src/index.ts @@ -22,4 +22,7 @@ export namespace OpenSwap { export type Token = Types.Token export type TokenResponse = Types.TokenResponse export type TokenAddress = Types.TokenAddress + + export type PriceAddress = Types.PriceAddress + export type PriceResponse = Types.PriceResponse } diff --git a/packages/openswap/src/price.spec.ts b/packages/openswap/src/price.spec.ts new file mode 100644 index 0000000000..6139a9d2bc --- /dev/null +++ b/packages/openswap/src/price.spec.ts @@ -0,0 +1,98 @@ +import {describe, expect, it, vi, Mocked} from 'vitest' +import {getPrice} from './price' +import {axiosClient} from './config' +import {PriceAddress, PriceResponse} from './types' + +vi.mock('./config.ts') + +describe('SwapPoolsApi', () => { + it('should get price for the pair token', async () => { + const mockAxios = axiosClient as Mocked + mockAxios.get.mockImplementationOnce(() => + Promise.resolve({ + status: 200, + data: mockedPriceResponse, + }), + ) + + const result = await getPrice( + {network: 'mainnet', client: mockAxios}, + { + ...getPriceParams, + }, + ) + expect(result).to.be.equal(mockedPriceResponse) + }) + + it('should throw error for invalid response', async () => { + const mockAxios = axiosClient as Mocked + await expect(async () => { + mockAxios.get.mockImplementationOnce(() => Promise.resolve({status: 500})) + await getPrice( + {network: 'preprod', client: mockAxios}, + {...getPriceParams}, + ) + }).rejects.toThrow('Failed to fetch price for token pair') + }) +}) + +const mockedPriceResponse: PriceResponse = { + baseDecimalPlaces: 6, + quoteDecimalPlaces: 6, + baseAddress: { + policyId: '', + name: '', + }, + quoteAddress: { + policyId: '29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6', + name: '4d494e', + }, + askPrice: 0.08209814208, + bidPrice: 0.06319999985, + price: 0.07080044463, + volume: { + base: '14735349', + quote: '211287611', + }, + volumeAggregator: { + minswap: { + quote: 107413106646, + base: 7651672996, + }, + sundaeswap: { + quote: 566084169, + base: 39000000, + }, + vyfi: { + quote: 12370434748, + base: 879028993, + }, + }, + volumeTotal: { + base: 8584437338, + quote: 120560913174, + }, + volumeChange: { + base: 0, + quote: 0, + }, + priceChange: { + '24h': '-0.2374956426253183', + '7d': '8.757469657697857', + }, + marketCap: 68873484244745.086, +} as const + +const getPriceParams: { + baseToken: PriceAddress + quoteToken: PriceAddress +} = { + baseToken: { + policyId: '', + name: '', + }, + quoteToken: { + policyId: '29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6', + name: '4d494e', + }, +} as const diff --git a/packages/openswap/src/price.ts b/packages/openswap/src/price.ts new file mode 100644 index 0000000000..ba46cd1ce8 --- /dev/null +++ b/packages/openswap/src/price.ts @@ -0,0 +1,30 @@ +import {SWAP_API_ENDPOINTS} from './config' +import type {ApiDeps, PriceAddress, PriceResponse} from './types' + +export async function getPrice( + deps: ApiDeps, + args: {baseToken: PriceAddress; quoteToken: PriceAddress}, +): Promise { + const {baseToken, quoteToken} = args + const {network, client} = deps + const params: {[key: string]: string} = { + 'base-policy-id': baseToken.policyId, + 'base-token-name': baseToken.policyId, + 'quote-policy-id': quoteToken.policyId, + 'quote-token-name': quoteToken.policyId, + } + + const apiUrl = SWAP_API_ENDPOINTS[network].getPrice + const response = await client.get('', { + baseURL: apiUrl, + params, + }) + + if (response.status !== 200) { + throw new Error('Failed to fetch price for token pair', { + cause: response.data, + }) + } + + return response.data +} diff --git a/packages/openswap/src/types.ts b/packages/openswap/src/types.ts index 29d8ea7124..c4964ac286 100644 --- a/packages/openswap/src/types.ts +++ b/packages/openswap/src/types.ts @@ -176,3 +176,45 @@ export type ApiDeps = { network: Network client: AxiosInstance } + +export type PriceAddress = { + policyId: string + name: string +} + +type VolumeAggregator = { + [key in Protocol]?: { + quote: number + base: number + } +} + +type PriceChange = { + '24h': string + '7d': string +} + +export type PriceResponse = { + baseDecimalPlaces: number + quoteDecimalPlaces: number + baseAddress: PriceAddress + quoteAddress: PriceAddress + askPrice: number + bidPrice: number + price: number + volume: { + base: string + quote: string + } + volumeAggregator: VolumeAggregator + volumeTotal: { + base: number + quote: number + } + volumeChange: { + base: number + quote: number + } + priceChange: PriceChange + marketCap: number +} diff --git a/packages/swap/src/adapters/openswap-api/api.test.ts b/packages/swap/src/adapters/openswap-api/api.test.ts index 2a015340a7..01b09d32bf 100644 --- a/packages/swap/src/adapters/openswap-api/api.test.ts +++ b/packages/swap/src/adapters/openswap-api/api.test.ts @@ -14,6 +14,7 @@ describe('swapApiMaker', () => { beforeEach(() => { jest.clearAllMocks() mockOpenSwapApi = { + getPrice: jest.fn(), cancelOrder: jest.fn(), createOrder: jest.fn(), getOrders: jest.fn(), @@ -302,4 +303,32 @@ describe('swapApiMaker', () => { expect(mockOpenSwapApi.getPools).not.toHaveBeenCalled() }) }) + + describe('getPrice', () => { + it('mainnet', async () => { + mockOpenSwapApi.getPrice = jest + .fn() + .mockResolvedValue(openswapMocks.getPrice) + + const api = swapApiMaker( + { + isMainnet: true, + stakingKey, + primaryTokenId, + }, + { + openswap: mockOpenSwapApi, + }, + ) + + const result = await api.getPrice({ + baseToken: '', + quoteToken: + '29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6.4d494e', + }) + + expect(result).toBe(0.07080044463) + expect(mockOpenSwapApi.getPrice).toHaveBeenCalledTimes(1) + }) + }) }) diff --git a/packages/swap/src/adapters/openswap-api/api.ts b/packages/swap/src/adapters/openswap-api/api.ts index bf48cd8b93..882b95dab5 100644 --- a/packages/swap/src/adapters/openswap-api/api.ts +++ b/packages/swap/src/adapters/openswap-api/api.ts @@ -91,7 +91,24 @@ export const swapApiMaker = ( .then(transformers.asYoroiPools) } + const getPrice: Swap.Api['getPrice'] = async ({baseToken, quoteToken}) => { + const opBaseToken = transformers.asOpenswapPriceTokenAddress(baseToken) + const opQuoteToken = transformers.asOpenswapPriceTokenAddress(quoteToken) + + return api + .getPrice({ + baseToken: { + ...opBaseToken, + }, + quoteToken: { + ...opQuoteToken, + }, + }) + .then((response) => response.price) + } + return { + getPrice, getOpenOrders, cancelOrder, createOrder, diff --git a/packages/swap/src/adapters/openswap-api/openswap.mocks.ts b/packages/swap/src/adapters/openswap-api/openswap.mocks.ts index ed914fd720..38e21eee17 100644 --- a/packages/swap/src/adapters/openswap-api/openswap.mocks.ts +++ b/packages/swap/src/adapters/openswap-api/openswap.mocks.ts @@ -441,8 +441,56 @@ const getPools: OpenSwap.Pool[] = [ }, ] +const getPrice: OpenSwap.PriceResponse = { + baseDecimalPlaces: 6, + quoteDecimalPlaces: 6, + baseAddress: { + policyId: '', + name: '', + }, + quoteAddress: { + policyId: '29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6', + name: '4d494e', + }, + askPrice: 0.08209814208, + bidPrice: 0.06319999985, + price: 0.07080044463, + volume: { + base: '14735349', + quote: '211287611', + }, + volumeAggregator: { + minswap: { + quote: 107413106646, + base: 7651672996, + }, + sundaeswap: { + quote: 566084169, + base: 39000000, + }, + vyfi: { + quote: 12370434748, + base: 879028993, + }, + }, + volumeTotal: { + base: 8584437338, + quote: 120560913174, + }, + volumeChange: { + base: 0, + quote: 0, + }, + priceChange: { + '24h': '-0.2374956426253183', + '7d': '8.757469657697857', + }, + marketCap: 68873484244745.086, +} + export const openswapMocks = { getTokens, + getPrice, getCompletedOrders, getOpenOrders, getPools, diff --git a/packages/swap/src/helpers/transformers.test.ts b/packages/swap/src/helpers/transformers.test.ts index 77c797cb37..405cf46495 100644 --- a/packages/swap/src/helpers/transformers.test.ts +++ b/packages/swap/src/helpers/transformers.test.ts @@ -151,6 +151,25 @@ describe('asOpensawpTokenId (TokenAddress)', () => { }) }) +describe('asOpensawpPriceTokenAddress (PriceAddress)', () => { + it('success', () => { + const result = transformers.asOpenswapPriceTokenAddress( + '1f7a58a1aa1e6b047a42109ade331ce26c9c2cce027d043ff264fb1f.425249434b53', + ) + expect(result).toEqual({ + policyId: '1f7a58a1aa1e6b047a42109ade331ce26c9c2cce027d043ff264fb1f', + name: '425249434b53', + }) + }) + it('success primary token (empty values)', () => { + const result = transformers.asOpenswapPriceTokenAddress('' as any) + expect(result).toEqual({ + policyId: '', + name: '', + }) + }) +}) + describe('asTokenFingerprint', () => { it('success', () => { const full = asTokenFingerprint({ diff --git a/packages/swap/src/helpers/transformers.ts b/packages/swap/src/helpers/transformers.ts index 880dda8b1d..197e07b166 100644 --- a/packages/swap/src/helpers/transformers.ts +++ b/packages/swap/src/helpers/transformers.ts @@ -21,6 +21,15 @@ export const transformersMaker = ( } } + const asOpenswapPriceTokenAddress = (yoroiTokenId: string) => { + const [policyId, name = ''] = yoroiTokenId.split('.') as [string, string?] + // we dont convert to '.' or 'lovelace' only '' + return { + policyId, + name, + } + } + const asYoroiTokenId = ({ policyId, name, @@ -177,6 +186,7 @@ export const transformersMaker = ( return { asOpenswapTokenId, + asOpenswapPriceTokenAddress, asOpenswapAmount, asYoroiTokenId, diff --git a/packages/swap/src/manager.mocks.ts b/packages/swap/src/manager.mocks.ts index 1c253f3081..27ea558791 100644 --- a/packages/swap/src/manager.mocks.ts +++ b/packages/swap/src/manager.mocks.ts @@ -82,6 +82,16 @@ const getPools = { }, } +const getPrice = { + success: () => Promise.resolve(1), + delayed: (timeout?: number) => delayedResponse({data: 1, timeout}), + empty: () => Promise.resolve(), + loading, + error: { + unknown: unknownError, + }, +} + const getTokens = { success: () => Promise.resolve(listPairsByTokenResponse), delayed: (timeout?: number) => @@ -140,6 +150,7 @@ export const swapManagerMocks = { createOrder, cancelOrder, + getPrice, getOpenOrders, getCompletedOrders, getPools, @@ -168,6 +179,9 @@ export const mockSwapManager: Swap.Manager = { byToken: getTokens.success, }, }, + price: { + byPair: getPrice.success, + }, slippage: slippage.success, clearStorage: clear.success, primaryTokenId: '', @@ -188,6 +202,9 @@ export const mockSwapManagerDefault: Swap.Manager = { byPair: getPools.error.unknown, }, }, + price: { + byPair: getPrice.error.unknown, + }, pairs: { list: { byToken: getTokens.error.unknown, diff --git a/packages/swap/src/manager.test.ts b/packages/swap/src/manager.test.ts index 520f34d0c2..1b43e919b4 100644 --- a/packages/swap/src/manager.test.ts +++ b/packages/swap/src/manager.test.ts @@ -19,6 +19,7 @@ describe('swapManagerMaker', () => { cancelOrder: jest.fn(), createOrder: jest.fn(), getOpenOrders: jest.fn(), + getPrice: jest.fn(), getPools: jest.fn(), getTokens: jest.fn(), getCompletedOrders: jest.fn(), diff --git a/packages/swap/src/manager.ts b/packages/swap/src/manager.ts index 9014335e13..bd1f23c253 100644 --- a/packages/swap/src/manager.ts +++ b/packages/swap/src/manager.ts @@ -6,6 +6,7 @@ export const swapManagerMaker = ( ): Readonly => { const {clear: clearStorage, slippage} = swapStorage const { + getPrice, getPools, getOpenOrders, getCompletedOrders, @@ -31,6 +32,10 @@ export const swapManagerMaker = ( } as const, } + const price = { + byPair: getPrice, + } as const + const pools = { list: { byPair: getPools, @@ -38,6 +43,7 @@ export const swapManagerMaker = ( } return { + price, clearStorage, slippage, order, diff --git a/packages/types/src/swap/api.ts b/packages/types/src/swap/api.ts index f84ddd0842..c5f85a20fc 100644 --- a/packages/types/src/swap/api.ts +++ b/packages/types/src/swap/api.ts @@ -18,6 +18,10 @@ export interface SwapApi { tokenB: BalanceToken['info']['id'] }): Promise getTokens(tokenIdBase: BalanceToken['info']['id']): Promise + getPrice(args: { + baseToken: BalanceToken['info']['id'] + quoteToken: BalanceToken['info']['id'] + }): Promise stakingKey: string primaryTokenId: BalanceToken['info']['id'] } diff --git a/packages/types/src/swap/manager.ts b/packages/types/src/swap/manager.ts index c5b2ec1b86..51e6d2faa7 100644 --- a/packages/types/src/swap/manager.ts +++ b/packages/types/src/swap/manager.ts @@ -18,6 +18,9 @@ export type SwapManager = Readonly<{ byToken: SwapApi['getTokens'] } } + price: { + byPair: SwapApi['getPrice'] + } pools: { list: { byPair: SwapApi['getPools'] From d33d8106e77a0863a40102b6226a3411138df7ec Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Wed, 4 Oct 2023 08:49:25 +0100 Subject: [PATCH 19/67] wip: state --- .../messages/src/yoroi-wallets/auth/auth.json | 24 ++++++------- packages/openswap/src/types.ts | 10 +++--- .../reactjs/provider/SwapProvider.tsx | 16 ++++++--- .../translators/reactjs/state/state.test.ts | 21 +++++++++++ .../src/translators/reactjs/state/state.ts | 36 +++++++++++++------ 5 files changed, 73 insertions(+), 34 deletions(-) diff --git a/apps/wallet-mobile/translations/messages/src/yoroi-wallets/auth/auth.json b/apps/wallet-mobile/translations/messages/src/yoroi-wallets/auth/auth.json index de9c073a1f..e048120d6d 100644 --- a/apps/wallet-mobile/translations/messages/src/yoroi-wallets/auth/auth.json +++ b/apps/wallet-mobile/translations/messages/src/yoroi-wallets/auth/auth.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Authorize", "file": "src/yoroi-wallets/auth/auth.ts", "start": { - "line": 255, + "line": 254, "column": 13, - "index": 8429 + "index": 8406 }, "end": { - "line": 258, + "line": 257, "column": 3, - "index": 8536 + "index": 8513 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!Too many attempts", "file": "src/yoroi-wallets/auth/auth.ts", "start": { - "line": 259, + "line": 258, "column": 19, - "index": 8557 + "index": 8534 }, "end": { - "line": 262, + "line": 261, "column": 3, - "index": 8668 + "index": 8645 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!Unknown error!", "file": "src/yoroi-wallets/auth/auth.ts", "start": { - "line": 263, + "line": 262, "column": 16, - "index": 8686 + "index": 8663 }, "end": { - "line": 266, + "line": 265, "column": 3, - "index": 8793 + "index": 8770 } } ] \ No newline at end of file diff --git a/packages/openswap/src/types.ts b/packages/openswap/src/types.ts index c4964ac286..b9fdb2198d 100644 --- a/packages/openswap/src/types.ts +++ b/packages/openswap/src/types.ts @@ -189,11 +189,6 @@ type VolumeAggregator = { } } -type PriceChange = { - '24h': string - '7d': string -} - export type PriceResponse = { baseDecimalPlaces: number quoteDecimalPlaces: number @@ -215,6 +210,9 @@ export type PriceResponse = { base: number quote: number } - priceChange: PriceChange + priceChange: { + '24h': string + '7d': string + } marketCap: number } diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx index c58666fe13..89ab02c7aa 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx @@ -88,11 +88,17 @@ export const SwapProvider = ({ lpTokenHeldChanged: (amount: Balance.Amount | undefined) => { dispatch({type: SwapCreateOrderActionType.LpTokenHeldChanged, amount}) }, - buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { - dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, tokenId}) - }, - sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { - dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, tokenId}) + buyTokenIdChanged: (payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + }) => { + dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, payload}) + }, + sellTokenIdChanged: (payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + }) => { + dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, payload}) }, poolPairsChanged: (pools: ReadonlyArray) => { dispatch({type: SwapCreateOrderActionType.PoolPairsChanged, pools}) diff --git a/packages/swap/src/translators/reactjs/state/state.test.ts b/packages/swap/src/translators/reactjs/state/state.test.ts index 691d166b72..de75d21d87 100644 --- a/packages/swap/src/translators/reactjs/state/state.test.ts +++ b/packages/swap/src/translators/reactjs/state/state.test.ts @@ -281,4 +281,25 @@ describe('State Actions', () => { const state = combinedSwapReducers(mockSwapStateDefault, action) expect(state).toEqual(expectedState) }) + + // + // TODO: implement + it('SellTokenIdChanged', () => { + expect('todo').toBeDefined() + }) + it('BuyTokenIdChanged', () => { + expect('todo').toBeDefined() + }) + it('SellQuantityChanged', () => { + expect('todo').toBeDefined() + }) + it('BuyQuantityChanged', () => { + expect('todo').toBeDefined() + }) + it('PoolPairsChanged', () => { + expect('todo').toBeDefined() + }) + it('LpTokenHeldChanged', () => { + expect('todo').toBeDefined() + }) }) diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index f3c2297990..f65e0ebe84 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -31,6 +31,7 @@ export type SwapOrderCalulation = Readonly<{ }> export type SwapState = Readonly<{ + // TODO: CreateOrderData should be build at request time, and unlinked from the state createOrder: Omit & { type: Swap.OrderType marketPrice: Balance.Quantity @@ -69,8 +70,14 @@ export type SwapCreateOrderActions = Readonly<{ // TODO: when changing quantity/token should receive & update the ADA pair along with it sellQuantityChanged: (quantity: Balance.Quantity) => void buyQuantityChanged: (quantity: Balance.Quantity) => void - sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void - buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void + sellTokenIdChanged: (payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + }) => void + buyTokenIdChanged: (payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + }) => void poolPairsChanged: (pools: ReadonlyArray) => void lpTokenHeldChanged: (amount: Balance.Amount | undefined) => void }> @@ -141,11 +148,17 @@ export type SwapCreateOrderAction = } | { type: SwapCreateOrderActionType.SellTokenIdChanged - tokenId: Balance.TokenInfo['id'] + payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + } } | { type: SwapCreateOrderActionType.BuyTokenIdChanged - tokenId: Balance.TokenInfo['id'] + payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + } } | { type: SwapCreateOrderActionType.PoolPairsChanged @@ -508,7 +521,8 @@ const createOrderReducer = ( // TODO: this should have the pools list too case SwapCreateOrderActionType.SellTokenIdChanged: - draft.createOrder.amounts.sell.tokenId = action.tokenId + draft.createOrder.amounts.sell.tokenId = action.payload.tokenId + draft.createOrder.pools = [...action.payload.pools] draft.createOrder.calculations = makeOrderCalculations({ orderType: state.createOrder.type, @@ -516,7 +530,7 @@ const createOrderReducer = ( limitPrice: state.createOrder.limitPrice, slippage: state.createOrder.slippage, ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + pools: draft.createOrder.pools, primaryTokenId: '', lpTokenHeld: state.createOrder.lpTokenHeld, action: action.type, @@ -526,7 +540,8 @@ const createOrderReducer = ( // TODO: this should have the pools list too case SwapCreateOrderActionType.BuyTokenIdChanged: - draft.createOrder.amounts.buy.tokenId = action.tokenId + draft.createOrder.amounts.buy.tokenId = action.payload.tokenId + draft.createOrder.pools = [...action.payload.pools] draft.createOrder.calculations = makeOrderCalculations({ orderType: state.createOrder.type, @@ -534,7 +549,7 @@ const createOrderReducer = ( limitPrice: state.createOrder.limitPrice, slippage: state.createOrder.slippage, ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + pools: draft.createOrder.pools, primaryTokenId: '', lpTokenHeld: state.createOrder.lpTokenHeld, action: action.type, @@ -560,15 +575,14 @@ const createOrderReducer = ( break case SwapCreateOrderActionType.PoolPairsChanged: - const pools = [...action.pools] - draft.createOrder.pools = pools + draft.createOrder.pools = [...action.pools] draft.createOrder.calculations = makeOrderCalculations({ orderType: state.createOrder.type, amounts: state.createOrder.amounts, limitPrice: state.createOrder.limitPrice, slippage: state.createOrder.slippage, ptPrices: state.createOrder.ptPrices, - pools: pools, + pools: draft.createOrder.pools, primaryTokenId: '', lpTokenHeld: state.createOrder.lpTokenHeld, action: action.type, From db0f741cb4edda8161abe2579bf9b59395c78233 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Wed, 4 Oct 2023 08:59:10 +0100 Subject: [PATCH 20/67] wip: calcs --- .../swap/src/helpers/orders/makeOrderCalculations.ts | 12 ++++++++++++ packages/swap/src/translators/reactjs/state/state.ts | 1 + 2 files changed, 13 insertions(+) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index f4aacbb670..5bf2a55a38 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -11,6 +11,7 @@ import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' import {getSellAmount} from './getSellAmount' import {asQuantity} from '../../utils/asQuantity' +import {Quantities} from 'utils/quantities' export const makeOrderCalculations = ({ orderType, @@ -33,6 +34,7 @@ export const makeOrderCalculations = ({ buy: `${number}` | undefined sell: `${number}` | undefined } + hasSupply: boolean, pools: ReadonlyArray lpTokenHeld: Balance.Amount | undefined slippage: number @@ -159,6 +161,15 @@ export const makeOrderCalculations = ({ .times(100) .toString() + const poolSupply = + buy.tokenId === pool.tokenA.tokenId + ? pool.tokenA.quantity + : pool.tokenB.quantity + const hasSupply = !Quantities.isGreaterThan( + buy.quantity, + poolSupply ?? Quantities.zero, + ) + const orderCalculation: SwapOrderCalulation = { cost: { batcherFee: pool.batcherFee, @@ -167,6 +178,7 @@ export const makeOrderCalculations = ({ liquidityFee, }, buyAmountWithSlippage, + hasSupply, prices: { base: priceBase, market: marketPrice, diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index f65e0ebe84..ba7c297ca3 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -18,6 +18,7 @@ export type SwapOrderCalulation = Readonly<{ withSlippage: string withFeesAndSlippage: string } + hasSupply: boolean buyAmountWithSlippage: Balance.Amount cost: { liquidityFee: Balance.Amount From d3590db1a47273fc5058bb46bd376cadb44122d5 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Thu, 5 Oct 2023 18:42:08 +0200 Subject: [PATCH 21/67] Refactor calculaed state --- .../src/TxHistory/ActionsBanner.tsx | 10 +- .../Swap/common/AmountCard/AmountCard.tsx | 6 +- .../ConfirmRawTx/ConfirmRawTx.stories.tsx | 2 +- .../SelectPoolFromList/SelectPoolFromList.tsx | 6 +- .../src/features/Swap/common/mocks.ts | 47 +- .../src/features/Swap/common/useSwapTx.ts | 20 +- .../ConfirmTxScreen.stories.tsx | 6 +- .../ConfirmTxScreen/ConfirmTxScreen.tsx | 20 +- .../TransactionSummary.stories.tsx | 2 +- .../ConfirmTxScreen/TransactionSummary.tsx | 10 +- .../CreateOrder/CreateOrder.stories.tsx | 4 +- .../CreateOrder/CreateOrder.tsx | 81 ++- .../EditBuyAmount/EditBuyAmount.stories.tsx | 8 +- .../EditBuyAmount/EditBuyAmount.tsx | 17 +- .../SelectBuyTokenFromListScreen.tsx | 4 +- .../CreateOrder/EditLimitPrice.tsx | 22 +- .../SelectPoolFromListScreen.tsx | 6 +- .../CreateOrder/EditPool/ShowPoolActions.tsx | 25 +- .../EditSellAmount/EditSellAmount.stories.tsx | 8 +- .../EditSellAmount/EditSellAmount.tsx | 8 +- .../SelectSellTokenFromListScreen.tsx | 5 +- .../EditSlippage/EditSlippage.stories.tsx | 2 +- .../CreateOrder/EditSlippage/EditSlippage.tsx | 4 +- .../EditSlippageScreen/EditSlippageScreen.tsx | 6 +- .../LimitPriceWarning/LimitPriceWarning.tsx | 10 +- .../ShowTokenActions/TopTokenActions.tsx | 12 +- .../Swap/common/AmountCard/AmountCard.json | 20 +- packages/swap/package.json | 8 +- .../helpers/orders/makeOrderCalculations.ts | 113 ++-- .../helpers/orders/makePossibleMarketOrder.ts | 2 +- packages/swap/src/index.ts | 1 + .../reactjs/provider/SwapProvider.test.tsx | 155 +----- .../reactjs/provider/SwapProvider.tsx | 13 +- .../translators/reactjs/state/state.mocks.ts | 22 +- .../translators/reactjs/state/state.test.ts | 164 +----- .../src/translators/reactjs/state/state.ts | 505 ++++++++---------- 36 files changed, 473 insertions(+), 881 deletions(-) diff --git a/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx b/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx index 8bc93923d2..feb2b856fa 100644 --- a/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx +++ b/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx @@ -25,15 +25,15 @@ export const ActionsBanner = ({disabled = false}: {disabled: boolean}) => { const navigateTo = useNavigateTo() const wallet = useSelectedWallet() const {resetForm} = useSend() - const {createOrder} = useSwap() + const {orderData} = useSwap() const {track} = useMetrics() const sellTokenInfo = useTokenInfo({ wallet, - tokenId: createOrder.amounts.sell.tokenId, + tokenId: orderData.amounts.sell.tokenId, }) const buyTokenInfo = useTokenInfo({ wallet, - tokenId: createOrder.amounts.buy.tokenId, + tokenId: orderData.amounts.buy.tokenId, }) const handleOnBuy = () => { @@ -60,8 +60,8 @@ export const ActionsBanner = ({disabled = false}: {disabled: boolean}) => { {asset_name: sellTokenInfo.name, asset_ticker: sellTokenInfo.ticker, policy_id: sellTokenInfo.group}, ], to_asset: [{asset_name: buyTokenInfo.name, asset_ticker: buyTokenInfo.ticker, policy_id: buyTokenInfo.group}], - order_type: createOrder.type, - slippage_tolerance: createOrder.slippage, + order_type: orderData.type, + slippage_tolerance: orderData.slippage, }) navigateTo.swap() diff --git a/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx b/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx index 9e45adbc24..39feef0efc 100644 --- a/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx @@ -42,9 +42,9 @@ export const AmountCard = ({ const amountInputRef = useRef(inputRef?.current ?? null) const tokenInfo = useTokenInfo({wallet, tokenId}) - const {createOrder} = useSwap() + const {orderData} = useSwap() - const isSell = tokenId === createOrder.amounts.sell.tokenId + const isSell = tokenId === orderData.amounts.sell.tokenId const noTokenSelected = !touched @@ -118,7 +118,7 @@ export const AmountCard = ({ - {createOrder.selectedPool === undefined + {orderData.calculatedPool === undefined ? strings.noPool : isSell ? strings.notEnoughBalance diff --git a/apps/wallet-mobile/src/features/Swap/common/ConfirmRawTx/ConfirmRawTx.stories.tsx b/apps/wallet-mobile/src/features/Swap/common/ConfirmRawTx/ConfirmRawTx.stories.tsx index b65ea4543e..7fc76733fb 100644 --- a/apps/wallet-mobile/src/features/Swap/common/ConfirmRawTx/ConfirmRawTx.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/ConfirmRawTx/ConfirmRawTx.stories.tsx @@ -42,7 +42,7 @@ const Provider = ({children, wallet}: {children: React.ReactNode; wallet: YoroiW initialState={{ ...mockSwapStateDefault, unsignedTx: walletMocks.yoroiUnsignedTx, - createOrder: {...mocks.confirmTx.createOrder}, + orderData: {...mocks.confirmTx.orderData}, }} swapManager={{ ...mockSwapManager, diff --git a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx index 84077899a1..867ae849f0 100644 --- a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx @@ -19,15 +19,15 @@ type Props = { export const SelectPoolFromList = ({data = []}: Props) => { const strings = useStrings() const wallet = useSelectedWallet() - const {selectedPoolChanged, createOrder} = useSwap() + const {selectedPoolChanged, orderData} = useSwap() const {poolTouched} = useSwapTouched() - const [selectedCardIndex, setSelectedCardIndex] = useState(createOrder.selectedPool?.poolId) + const [selectedCardIndex, setSelectedCardIndex] = useState(orderData.selectedPoolId) const navigate = useNavigateTo() const {track} = useMetrics() const handleCardSelect = (pool: Swap.Pool) => { track.swapPoolChanged() - selectedPoolChanged(pool) + selectedPoolChanged(pool.poolId) setSelectedCardIndex(pool.poolId) poolTouched() navigate.startSwap() diff --git a/apps/wallet-mobile/src/features/Swap/common/mocks.ts b/apps/wallet-mobile/src/features/Swap/common/mocks.ts index c336ec767f..f803a6c48c 100644 --- a/apps/wallet-mobile/src/features/Swap/common/mocks.ts +++ b/apps/wallet-mobile/src/features/Swap/common/mocks.ts @@ -3,14 +3,12 @@ import {mockSwapStateDefault, SwapState} from '@yoroi/swap' import {mocks as walletMocks} from '../../../yoroi-wallets/mocks/wallet' import {asQuantity} from '../../../yoroi-wallets/utils' -type Type = 'market' | 'limit' - export const mocks = { confirmTx: { ...mockSwapStateDefault, yoroiUnsignedTx: walletMocks.yoroiUnsignedTx, - createOrder: { - address: '', + orderData: { + ...mockSwapStateDefault.orderData, amounts: { buy: { quantity: asQuantity(20467572) as `${number}`, @@ -18,30 +16,29 @@ export const mocks = { }, sell: {quantity: asQuantity(2000000), tokenId: ''}, }, - datum: '', - datumHash: '', limitPrice: '0.089' as `${number}`, - marketPrice: '0.089' as `${number}`, - selectedPool: { - batcherFee: {quantity: asQuantity(2500000), tokenId: ''}, - deposit: {quantity: asQuantity(2000000), tokenId: ''}, - fee: '0.05', - lastUpdate: '2023-09-08 09:56:13', - lpToken: { - quantity: asQuantity(68917682), - tokenId: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.6c702083', - }, - poolId: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.702083', - price: 0.0890390378168252, - provider: 'sundaeswap', - tokenA: {quantity: asQuantity(20630071), tokenId: ''}, - tokenB: { - quantity: asQuantity(231696922), - tokenId: '208a2ca888886921513cb777bb832a8dc685c04de990480151f12150.53484942414441', + selectedPool: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.702083', + pools: [ + { + batcherFee: {quantity: asQuantity(2500000), tokenId: ''}, + deposit: {quantity: asQuantity(2000000), tokenId: ''}, + fee: '0.05', + lastUpdate: '2023-09-08 09:56:13', + lpToken: { + quantity: asQuantity(68917682), + tokenId: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.6c702083', + }, + poolId: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.702083', + price: 0.0890390378168252, + provider: 'sundaeswap', + tokenA: {quantity: asQuantity(20630071), tokenId: ''}, + tokenB: { + quantity: asQuantity(231696922), + tokenId: '208a2ca888886921513cb777bb832a8dc685c04de990480151f12150.53484942414441', + }, }, - }, + ], slippage: 1, - type: 'market' as Type, }, } as SwapState, } diff --git a/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts b/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts index 7eee98b77a..c3571c5595 100644 --- a/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts +++ b/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts @@ -8,22 +8,22 @@ import {YoroiEntry, YoroiUnsignedTx} from '../../../yoroi-wallets/types' import {splitStringInto64CharArray} from '../../../yoroi-wallets/utils' export const useSwapTx = (options?: UseMutationOptions) => { - const {createOrder} = useSwap() - + const {orderData} = useSwap() + const pool = orderData.calculatedPool?.pool const metadata = [ { label: '674', data: { msg: splitStringInto64CharArray( JSON.stringify({ - provider: createOrder.selectedPool?.provider, - sellTokenId: createOrder.amounts.sell.tokenId, - sellQuantity: createOrder.amounts.sell.quantity, - buyTokenId: createOrder.amounts.buy.tokenId, - buyQuantity: createOrder.amounts.buy.quantity, - depositFee: createOrder.selectedPool?.deposit.quantity, - feeTokenId: createOrder.selectedPool?.deposit.tokenId, - poolId: createOrder.selectedPool?.poolId, + provider: pool?.provider, + sellTokenId: orderData.amounts.sell.tokenId, + sellQuantity: orderData.amounts.sell.quantity, + buyTokenId: orderData.amounts.buy.tokenId, + buyQuantity: orderData.amounts.buy.quantity, + depositFee: pool?.deposit.quantity, + feeTokenId: pool?.deposit.tokenId, + poolId: pool?.poolId, }), ), }, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.stories.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.stories.tsx index fe565d08e0..ad2bf6753a 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.stories.tsx @@ -26,7 +26,7 @@ const ConfirmTxWithPasswaordScreen = () => { initialState={{ ...mockSwapStateDefault, unsignedTx: walletMocks.yoroiUnsignedTx, - createOrder: {...mocks.confirmTx.createOrder}, + orderData: {...mocks.confirmTx.orderData}, }} swapManager={{ ...mockSwapManager, @@ -46,7 +46,7 @@ const ConfirmTxWithOSScreen = () => { initialState={{ ...mockSwapStateDefault, unsignedTx: walletMocks.yoroiUnsignedTx, - createOrder: {...mocks.confirmTx.createOrder}, + orderData: {...mocks.confirmTx.orderData}, }} swapManager={{ ...mockSwapManager, @@ -66,7 +66,7 @@ const ConfirmTxWithHWcreen = () => { initialState={{ ...mockSwapStateDefault, unsignedTx: walletMocks.yoroiUnsignedTx, - createOrder: {...mocks.confirmTx.createOrder}, + orderData: {...mocks.confirmTx.orderData}, }} swapManager={{ ...mockSwapManager, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx index fdeb843af2..3de504c1ff 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx @@ -30,14 +30,14 @@ export const ConfirmTxScreen = () => { const navigate = useNavigateTo() const {track} = useMetrics() - const {unsignedTx, createOrder} = useSwap() + const {unsignedTx, orderData} = useSwap() const sellTokenInfo = useTokenInfo({ wallet, - tokenId: createOrder.amounts.sell.tokenId, + tokenId: orderData.amounts.sell.tokenId, }) const buyTokenInfo = useTokenInfo({ wallet, - tokenId: createOrder.amounts.buy.tokenId, + tokenId: orderData.amounts.buy.tokenId, }) const {authWithOs, isLoading: authenticating} = useAuthOsWithEasyConfirmation( @@ -51,7 +51,7 @@ export const ConfirmTxScreen = () => { signTx: {useErrorBoundary: true}, submitTx: { onSuccess: () => { - if (!createOrder.selectedPool) return + if (orderData.calculatedPool === undefined) return track.swapOrderSubmitted({ from_asset: [ {asset_name: sellTokenInfo.name, asset_ticker: sellTokenInfo.ticker, policy_id: sellTokenInfo.group}, @@ -59,12 +59,12 @@ export const ConfirmTxScreen = () => { to_asset: [ {asset_name: buyTokenInfo.name, asset_ticker: buyTokenInfo.ticker, policy_id: buyTokenInfo.group}, ], - order_type: createOrder.type, - slippage_tolerance: createOrder.slippage, - from_amount: createOrder.amounts.sell.quantity, - to_amount: createOrder.amounts.buy.quantity, - pool_source: createOrder.selectedPool.provider, - swap_fees: Number(createOrder.selectedPool.fee), + order_type: orderData.type, + slippage_tolerance: orderData.slippage, + from_amount: orderData.amounts.sell.quantity, + to_amount: orderData.amounts.buy.quantity, + pool_source: orderData.calculatedPool.pool.provider, + swap_fees: Number(orderData.calculatedPool.cost.batcherFee), }) navigate.submittedTx() diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.stories.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.stories.tsx index 69b6cf9dea..9e93d69c1f 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.stories.tsx @@ -32,7 +32,7 @@ const TxSummary = () => { initialState={{ ...mockSwapStateDefault, unsignedTx: walletMocks.yoroiUnsignedTx, - createOrder: {...mocks.confirmTx.createOrder}, + orderData: {...mocks.confirmTx.orderData}, }} swapManager={{ ...mockSwapManager, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx index 1379101ec3..dc97fa2044 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx @@ -21,8 +21,8 @@ export const TransactionSummary = () => { const strings = useStrings() const wallet = useSelectedWallet() const {numberLocale} = useLanguage() - const {createOrder} = useSwap() - const {amounts, selectedPool} = createOrder + const {orderData} = useSwap() + const {amounts, calculatedPool} = orderData const buyTokenInfo = useTokenInfo({wallet, tokenId: amounts.buy.tokenId}) const tokenToBuyName = buyTokenInfo.ticker ?? buyTokenInfo.name @@ -32,7 +32,7 @@ export const TransactionSummary = () => { { label: strings.swapMinAdaTitle, value: `${Quantities.format( - selectedPool?.deposit?.quantity ?? Quantities.zero, + calculatedPool?.cost?.deposit?.quantity ?? Quantities.zero, Number(wallet.primaryTokenInfo.decimals), )} ${wallet.primaryTokenInfo.ticker}`, info: strings.swapMinAda, @@ -41,7 +41,7 @@ export const TransactionSummary = () => { label: strings.swapMinReceivedTitle, value: `${getMinAdaReceiveAfterSlippage( amounts.buy.quantity, - createOrder.slippage, + orderData.slippage, buyTokenInfo.decimals ?? 0, numberLocale, )} ${tokenToBuyName}`, @@ -50,7 +50,7 @@ export const TransactionSummary = () => { { label: strings.swapFeesTitle, value: `${Quantities.format( - createOrder.selectedPool?.batcherFee?.quantity ?? Quantities.zero, + calculatedPool?.cost?.batcherFee?.quantity ?? Quantities.zero, // TODO: Show all fees Number(wallet.primaryTokenInfo.decimals), )} ${wallet.primaryTokenInfo.ticker}`, info: strings.swapFees, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.stories.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.stories.tsx index 1e86c8ffee..5c5d319a2a 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.stories.tsx @@ -27,7 +27,7 @@ const Initial = () => { const MarketOrder = () => { const initialState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.type = 'market' + draft.orderData.type = 'market' }) return ( @@ -42,7 +42,7 @@ const MarketOrder = () => { const LimitOrder = () => { const initialState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.type = 'limit' + draft.orderData.type = 'limit' }) return ( diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx index 0884bc63f0..f578d65ec0 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx @@ -1,7 +1,7 @@ import {makeLimitOrder, makePossibleMarketOrder, useSwap, useSwapCreateOrder, useSwapPoolsByPair} from '@yoroi/swap' import {Swap} from '@yoroi/types' import BigNumber from 'bignumber.js' -import React, {useEffect, useMemo, useState} from 'react' +import React, {useEffect, useState} from 'react' import {KeyboardAvoidingView, Platform, StyleSheet, View, ViewProps} from 'react-native' import {ScrollView} from 'react-native-gesture-handler' @@ -31,37 +31,32 @@ const LIMIT_PRICE_WARNING_THRESHOLD = 0.1 // 10% export const CreateOrder = () => { const strings = useStrings() const navigation = useNavigateTo() - const {createOrder, selectedPoolChanged, unsignedTxChanged, txPayloadChanged} = useSwap() + const {orderData, poolPairsChanged, unsignedTxChanged} = useSwap() const wallet = useSelectedWallet() const {track} = useMetrics() const sellTokenInfo = useTokenInfo({ wallet, - tokenId: createOrder.amounts.sell.tokenId, + tokenId: orderData.amounts.sell.tokenId, }) const buyTokenInfo = useTokenInfo({ wallet, - tokenId: createOrder.amounts.buy.tokenId, + tokenId: orderData.amounts.buy.tokenId, }) const [showLimitPriceWarning, setShowLimitPriceWarning] = useState(false) const {isBuyTouched, isSellTouched, poolDefaulted} = useSwapTouched() const {poolList} = useSwapPoolsByPair({ - tokenA: createOrder.amounts.sell.tokenId ?? '', - tokenB: createOrder.amounts.buy.tokenId ?? '', + tokenA: orderData.amounts.sell.tokenId ?? '', + tokenB: orderData.amounts.buy.tokenId ?? '', }) - const bestPool = useMemo(() => { - if (poolList !== undefined && poolList.length > 0) { - return poolList.sort((a, b) => a.price - b.price).find(() => true) - } - return undefined - }, [poolList]) + useEffect(() => { + poolPairsChanged(poolList ?? []) + }, [poolPairsChanged, poolList]) useEffect(() => { - selectedPoolChanged(bestPool) - poolDefaulted() - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [poolDefaulted, selectedPoolChanged, bestPool?.poolId, bestPool?.price]) + if (orderData.selectedPoolId === orderData.bestPool?.pool.poolId) poolDefaulted() + }, [orderData.selectedPoolId, orderData.bestPool, poolDefaulted]) const {createUnsignedTx, isLoading} = useSwapTx({ onSuccess: (yoroiUnsignedTx) => { @@ -76,21 +71,20 @@ export const CreateOrder = () => { const {createOrderData} = useSwapCreateOrder({ onSuccess: (data: Swap.CreateOrderResponse) => { - if (data?.contractAddress !== undefined && createOrder.selectedPool !== undefined) { - const {amounts, limitPrice, address, slippage, selectedPool} = createOrder + if (data?.contractAddress !== undefined && orderData.calculatedPool?.pool !== undefined) { + const {amounts, limitPrice, slippage, calculatedPool} = orderData const entry = createYoroiEntry( { amounts, limitPrice, - address, + address: data.contractAddress, slippage, - selectedPool, + selectedPool: calculatedPool.pool, }, data.contractAddress, wallet, ) const datum = {data: data.datum} - txPayloadChanged({datum: data.datum, datumHash: data.datumHash, contractAddress: data.contractAddress}) createUnsignedTx({entry, datum}) } }, @@ -102,24 +96,27 @@ export const CreateOrder = () => { const disabled = !isBuyTouched || !isSellTouched || - Quantities.isZero(createOrder.amounts.buy.quantity) || - Quantities.isZero(createOrder.amounts.sell.quantity) || - (createOrder.type === 'limit' && createOrder.limitPrice !== undefined && Quantities.isZero(createOrder.limitPrice)) + Quantities.isZero(orderData.amounts.buy.quantity) || + Quantities.isZero(orderData.amounts.sell.quantity) || + (orderData.type === 'limit' && orderData.limitPrice !== undefined && Quantities.isZero(orderData.limitPrice)) const swap = () => { - if (!createOrder.selectedPool) return + if (orderData.calculatedPool === undefined) return track.swapOrderSelected({ from_asset: [ {asset_name: sellTokenInfo.name, asset_ticker: sellTokenInfo.ticker, policy_id: sellTokenInfo.group}, ], to_asset: [{asset_name: buyTokenInfo.name, asset_ticker: buyTokenInfo.ticker, policy_id: buyTokenInfo.group}], - order_type: createOrder.type, - slippage_tolerance: createOrder.slippage, - from_amount: createOrder.amounts.sell.quantity, - to_amount: createOrder.amounts.buy.quantity, - pool_source: createOrder.selectedPool.provider, + order_type: orderData.type, + slippage_tolerance: orderData.slippage, + from_amount: orderData.amounts.sell.quantity, + to_amount: orderData.amounts.buy.quantity, + pool_source: orderData.calculatedPool.pool.provider, swap_fees: Number( - Quantities.denominated(createOrder.selectedPool.batcherFee.quantity, Number(wallet.primaryTokenInfo.decimals)), + Quantities.denominated( + orderData.calculatedPool.pool.batcherFee.quantity, + Number(wallet.primaryTokenInfo.decimals), + ), ), }) @@ -127,19 +124,18 @@ export const CreateOrder = () => { } const createUnsignedSwapTx = () => { - const {amounts} = createOrder const orderDetails = { - sell: amounts.sell, - buy: amounts.buy, - pools: poolList, - selectedPool: createOrder.selectedPool, - slippage: createOrder.slippage, + sell: orderData.amounts.sell, + buy: orderData.amounts.buy, + pools: orderData.pools, + selectedPool: orderData.calculatedPool?.pool, + slippage: orderData.slippage, address: wallet.externalAddresses[0], } if (orderDetails.pools === undefined || orderDetails.selectedPool === undefined) return - if (createOrder.type === 'market') { + if (orderData.type === 'market') { const orderResult: Swap.CreateOrderData | undefined = makePossibleMarketOrder( orderDetails.sell, orderDetails.buy, @@ -150,7 +146,7 @@ export const CreateOrder = () => { if (orderResult) createSwapOrder(orderResult) } - if (createOrder.type === 'limit') { + if (orderData.type === 'limit') { const orderResult = makeLimitOrder( orderDetails.sell, orderDetails.buy, @@ -175,9 +171,10 @@ export const CreateOrder = () => { } const handleOnSwap = () => { - if (createOrder.type === 'limit' && createOrder.limitPrice !== undefined) { - const marketPrice = new BigNumber(createOrder.marketPrice) - const limitPrice = new BigNumber(createOrder.limitPrice) + if (orderData.marketPrice === undefined) return + if (orderData.type === 'limit' && orderData.limitPrice !== undefined) { + const marketPrice = new BigNumber(orderData.marketPrice) + const limitPrice = new BigNumber(orderData.limitPrice) if (limitPrice.isGreaterThan(marketPrice.times(1 + LIMIT_PRICE_WARNING_THRESHOLD))) { setShowLimitPriceWarning(true) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.stories.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.stories.tsx index 85c668b689..e942f0c1b8 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.stories.tsx @@ -49,7 +49,7 @@ const mockWallet = produce(mocks.wallet, (draft) => { ] }) const mockSwapStateOtherToken = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts = { + draft.orderData.amounts = { sell: { tokenId: '2a0879034f23ea48ba28dc1c15b056bd63b8cf0cab9733da92add22f.444444', quantity: '500000', @@ -61,7 +61,7 @@ const mockSwapStateOtherToken = produce(mockSwapStateDefault, (draft) => { } }) const mockSwapStateSameToken = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts = { + draft.orderData.amounts = { sell: { tokenId: '648823ffdad1610b4162f4dbc87bd47f6f9cf45d772ddef661eff198.7755534443', quantity: '500000', @@ -73,10 +73,10 @@ const mockSwapStateSameToken = produce(mockSwapStateDefault, (draft) => { } }) const mockSwapStateUnamedToken = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.sell.tokenId = '2a0879034f23ea48ba28dc1c15b056bd63b8cf0cab9733da92add22f.' + draft.orderData.amounts.sell.tokenId = '2a0879034f23ea48ba28dc1c15b056bd63b8cf0cab9733da92add22f.' }) const mockSwapStateWithIconBigDecimals = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.buy = { + draft.orderData.amounts.buy = { tokenId: '1d129dc9c03f95a863489883914f05a52e13135994a32f0cbeacc65e.74484f444c53', quantity: '12301234567', } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx index 8d987fda81..e7815ca952 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx @@ -19,9 +19,10 @@ export const EditBuyAmount = () => { const {numberLocale} = useLanguage() const inputRef = React.useRef(null) - const {createOrder, buyAmountChanged} = useSwap() + const {orderData, buyQuantityChanged} = useSwap() const {isBuyTouched} = useSwapTouched() - const {tokenId, quantity} = createOrder.amounts.buy + const pool = orderData.calculatedPool?.pool + const {tokenId, quantity} = orderData.amounts.buy const tokenInfo = useTokenInfo({wallet, tokenId}) const {decimals} = tokenInfo const balance = useBalance({wallet, tokenId}) @@ -34,19 +35,15 @@ export const EditBuyAmount = () => { } }, [isBuyTouched, quantity, tokenInfo.decimals]) - const poolSupply = - tokenId === createOrder?.selectedPool?.tokenA.tokenId - ? createOrder.selectedPool?.tokenA.quantity - : createOrder.selectedPool?.tokenB.quantity + const poolSupply = tokenId === pool?.tokenA.tokenId ? pool?.tokenA.quantity : pool?.tokenB.quantity const hasSupply = !Quantities.isGreaterThan(quantity, poolSupply ?? Quantities.zero) - const showError = - (!Quantities.isZero(quantity) && !hasSupply) || (isBuyTouched && createOrder.selectedPool === undefined) + const showError = (!Quantities.isZero(quantity) && !hasSupply) || (isBuyTouched && pool === undefined) const onChangeQuantity = (text: string) => { try { const [input, quantity] = Quantities.parseFromText(text, decimals ?? 0, numberLocale) setInputValue(text === '' ? text : input) - buyAmountChanged({tokenId, quantity}) + buyQuantityChanged(quantity) } catch (error) { Logger.error('SwapAmountScreen::onChangeQuantity', error) } @@ -63,7 +60,7 @@ export const EditBuyAmount = () => { navigateTo={navigate.selectBuyToken} touched={isBuyTouched} inputRef={inputRef} - inputEditable={createOrder.selectedPool !== undefined} + inputEditable={pool !== undefined} /> ) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 78c4d9c852..817c4a84c5 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -178,7 +178,7 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenForList: TokenForList; wallet: YoroiWallet} const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {buyAmountChanged} = useSwap() + const {buyTokenIdChanged} = useSwap() const {buyTouched} = useSwapTouched() const navigateTo = useNavigateTo() @@ -190,7 +190,7 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], }) buyTouched() - buyAmountChanged({tokenId: tokenForList.id, quantity: Quantities.zero}) + buyTokenIdChanged({tokenId: tokenForList.id, pools: []}) navigateTo.startSwap() closeSearch() } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx index 8e24fbb897..5c692acfd1 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx @@ -20,11 +20,11 @@ export const EditLimitPrice = () => { const [text, setText] = React.useState('') const wallet = useSelectedWallet() - const {createOrder, limitPriceChanged} = useSwap() - const sellTokenInfo = useTokenInfo({wallet, tokenId: createOrder.amounts.sell.tokenId}) - const buyTokenInfo = useTokenInfo({wallet, tokenId: createOrder.amounts.buy.tokenId}) + const {orderData, limitPriceChanged} = useSwap() + const sellTokenInfo = useTokenInfo({wallet, tokenId: orderData.amounts.sell.tokenId}) + const buyTokenInfo = useTokenInfo({wallet, tokenId: orderData.amounts.buy.tokenId}) const denomination = (sellTokenInfo.decimals ?? 0) - (buyTokenInfo.decimals ?? 0) - const disabled = createOrder.type === 'market' + const disabled = orderData.type === 'market' const {isBuyTouched, isSellTouched} = useSwapTouched() @@ -32,18 +32,12 @@ export const EditLimitPrice = () => { const tokenToBuyName = isBuyTouched ? buyTokenInfo.ticker ?? buyTokenInfo.name : '-' React.useEffect(() => { - setText(Quantities.format(createOrder.marketPrice, denomination, PRECISION)) - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [createOrder.marketPrice]) - - React.useEffect(() => { - if (createOrder.type === 'limit') { - setText(Quantities.format(createOrder?.limitPrice ?? Quantities.zero, denomination, PRECISION)) + if (orderData.type === 'limit') { + setText(Quantities.format(orderData.limitPrice ?? Quantities.zero, denomination, PRECISION)) } else { - setText(Quantities.format(createOrder.marketPrice, denomination, PRECISION)) + setText(Quantities.format(orderData.marketPrice, denomination, PRECISION)) } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [createOrder.type, createOrder.limitPrice]) + }, [orderData.type, orderData.limitPrice, orderData.amounts.sell, denomination, orderData.marketPrice]) const onChange = (text: string) => { const [formattedPrice, price] = Quantities.parseFromText(text, PRECISION, numberLocale) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx index 8ff507ade6..587c83cc58 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx @@ -10,11 +10,11 @@ import {useStrings} from '../../../../../common/strings' export const SelectPoolFromListScreen = () => { const strings = useStrings() - const {createOrder} = useSwap() + const {orderData} = useSwap() const {poolList} = useSwapPoolsByPair({ - tokenA: createOrder.amounts.sell.tokenId, - tokenB: createOrder.amounts.buy.tokenId, + tokenA: orderData.amounts.sell.tokenId, + tokenB: orderData.amounts.buy.tokenId, }) const poolCounter = Array.isArray(poolList) ? poolList.length : 0 diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx index 2721bf8af4..3ca04eac03 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx @@ -23,25 +23,25 @@ import {useSwapTouched} from '../../../../common/SwapFormProvider' export const ShowPoolActions = () => { const navigateTo = useNavigateTo() const {numberLocale} = useLanguage() - const {createOrder} = useSwap() + const {orderData} = useSwap() const strings = useStrings() const {isBuyTouched, isSellTouched, isPoolTouched} = useSwapTouched() - const {selectedPool, amounts} = createOrder + const {calculatedPool, amounts} = orderData const wallet = useSelectedWallet() const buyTokenInfo = useTokenInfo({wallet, tokenId: amounts.buy.tokenId}) const tokenName = buyTokenInfo.ticker ?? buyTokenInfo.name const [hiddenInfoOpenId, setHiddenInfoOpenId] = React.useState(null) - if (!isBuyTouched || !isSellTouched || selectedPool === undefined) { + if (!isBuyTouched || !isSellTouched || calculatedPool === undefined) { return <> } const totalAmount = Quantities.format(amounts.buy.quantity, buyTokenInfo.decimals ?? 0) - const id = selectedPool.poolId + const id = calculatedPool.pool.poolId const expanded = id === hiddenInfoOpenId - const poolProviderFormatted = capitalize(selectedPool.provider) - const poolStatus = isPoolTouched ? '' : ` ${strings.autoPool}` + const poolProviderFormatted = capitalize(calculatedPool.pool.provider) + const poolStatus = orderData.type === 'limit' && isPoolTouched ? '' : ` ${strings.autoPool}` const poolTitle = `${poolProviderFormatted}${poolStatus}` return ( @@ -51,7 +51,7 @@ export const ShowPoolActions = () => {
setHiddenInfoOpenId(hiddenInfoOpenId !== id ? id : null)} onPressLabel={() => { - if (createOrder.type === 'limit') { + if (orderData.type === 'limit') { navigateTo.selectPool() } else { setHiddenInfoOpenId(hiddenInfoOpenId !== id ? id : null) @@ -60,7 +60,7 @@ export const ShowPoolActions = () => { expanded={expanded} > - + @@ -70,14 +70,17 @@ export const ShowPoolActions = () => { } info={ } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.stories.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.stories.tsx index 29c79a88b7..ec6c6d27a6 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.stories.tsx @@ -43,16 +43,16 @@ const mockWallet = produce(mocks.wallet, (draft) => { ] }) const mockSwapStateNoBalance = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.sell.quantity = '3000000' + draft.orderData.amounts.sell.quantity = '3000000' }) const mockSwapStateSecodaryToken = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.sell.tokenId = '2a0879034f23ea48ba28dc1c15b056bd63b8cf0cab9733da92add22f.444444' + draft.orderData.amounts.sell.tokenId = '2a0879034f23ea48ba28dc1c15b056bd63b8cf0cab9733da92add22f.444444' }) const mockSwapStateUnamedToken = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.sell.tokenId = '2a0879034f23ea48ba28dc1c15b056bd63b8cf0cab9733da92add22f.' + draft.orderData.amounts.sell.tokenId = '2a0879034f23ea48ba28dc1c15b056bd63b8cf0cab9733da92add22f.' }) const mockSwapStateWithIconBigDecimals = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.sell = { + draft.orderData.amounts.sell = { tokenId: '1d129dc9c03f95a863489883914f05a52e13135994a32f0cbeacc65e.74484f444c53', quantity: '12301234567', } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx index 6293ad204d..61571fcf09 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx @@ -19,10 +19,10 @@ export const EditSellAmount = () => { const {numberLocale} = useLanguage() const inputRef = React.useRef(null) - const {createOrder, sellAmountChanged} = useSwap() + const {orderData, sellQuantityChanged} = useSwap() const {isSellTouched} = useSwapTouched() - const {tokenId, quantity} = createOrder.amounts.sell + const {tokenId, quantity} = orderData.amounts.sell const tokenInfo = useTokenInfo({wallet, tokenId}) const {decimals} = tokenInfo @@ -43,7 +43,7 @@ export const EditSellAmount = () => { try { const [input, quantity] = Quantities.parseFromText(text, decimals ?? 0, numberLocale) setInputValue(text === '' ? text : input) - sellAmountChanged({tokenId, quantity}) + sellQuantityChanged(quantity) } catch (error) { Logger.error('SwapAmountScreen::onChangeQuantity', error) } @@ -60,7 +60,7 @@ export const EditSellAmount = () => { navigateTo={navigate.selectSellToken} touched={isSellTouched} inputRef={inputRef} - inputEditable={createOrder.selectedPool !== undefined} + inputEditable={orderData.calculatedPool?.pool !== undefined} /> ) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx index aa810132a3..1c5b551a94 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx @@ -14,7 +14,6 @@ import {COLORS} from '../../../../../../../theme' import {sortTokenInfos} from '../../../../../../../utils' import {YoroiWallet} from '../../../../../../../yoroi-wallets/cardano/types' import {useAllTokenInfos, useBalance, useIsWalletEmpty} from '../../../../../../../yoroi-wallets/hooks' -import {Quantities} from '../../../../../../../yoroi-wallets/utils/utils' import {filterByFungibility} from '../../../../../../Send/common/filterByFungibility' import {NoAssetFoundImage} from '../../../../../../Send/common/NoAssetFoundImage' import {Counter} from '../../../../../common/Counter/Counter' @@ -84,7 +83,7 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenInfo: Balance.TokenInfo; wallet: YoroiWallet} const SelectableToken = ({tokenInfo, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {sellAmountChanged} = useSwap() + const {sellTokenIdChanged} = useSwap() const {sellTouched} = useSwapTouched() const navigateTo = useNavigateTo() const {track} = useMetrics() @@ -96,7 +95,7 @@ const SelectableToken = ({tokenInfo, wallet}: SelectableTokenProps) => { from_asset: [{asset_name: tokenInfo.name, asset_ticker: tokenInfo.ticker, policy_id: tokenInfo.group}], }) sellTouched() - sellAmountChanged({tokenId: tokenInfo.id, quantity: Quantities.zero}) + sellTokenIdChanged({tokenId: tokenInfo.id, pools: []}) navigateTo.startSwap() closeSearch() } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.stories.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.stories.tsx index 0b520dd6a7..b2a1e42cb8 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.stories.tsx @@ -25,7 +25,7 @@ storiesOf('Swap Edit Slippage', module) }) .add('big %', () => { const mockSwapStateBigSlippage = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.slippage = 99.123456789 + draft.orderData.slippage = 99.123456789 }) return ( diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.tsx index 6c8a37f16d..2558597e32 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippage.tsx @@ -9,14 +9,14 @@ import {ShowSlippageInfo} from './ShowSlippageInfo' export const EditSlippage = () => { const navigate = useNavigateTo() - const {createOrder} = useSwap() + const {orderData} = useSwap() return ( - {`${createOrder.slippage} %`} + {`${orderData.slippage} %`} diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippageScreen/EditSlippageScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippageScreen/EditSlippageScreen.tsx index 8328b08083..8f8047fbde 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippageScreen/EditSlippageScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSlippage/EditSlippageScreen/EditSlippageScreen.tsx @@ -50,10 +50,10 @@ const MAX_DECIMALS = 1 export const EditSlippageScreen = () => { const {numberLocale} = useLanguage() - const {slippageChanged, createOrder} = useSwap() - const defaultSelectedChoice = getChoiceBySlippage(createOrder.slippage, numberLocale) + const {slippageChanged, orderData} = useSwap() + const defaultSelectedChoice = getChoiceBySlippage(orderData.slippage, numberLocale) const defaultInputValue = - defaultSelectedChoice.label === 'Manual' ? new BigNumber(createOrder.slippage).toFormat(numberLocale) : '' + defaultSelectedChoice.label === 'Manual' ? new BigNumber(orderData.slippage).toFormat(numberLocale) : '' const [selectedChoiceLabel, setSelectedChoiceLabel] = useState(defaultSelectedChoice.label) const [inputValue, setInputValue] = useState(defaultInputValue) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx index 858a0b67a5..438815bad1 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx @@ -17,16 +17,16 @@ export interface LimitPriceWarningProps { } export const LimitPriceWarning = ({open, onClose, onSubmit}: LimitPriceWarningProps) => { - const {createOrder} = useSwap() + const {orderData} = useSwap() const {numberLocale} = useLanguage() const strings = useStrings() - const limitPrice = new BigNumber(createOrder.limitPrice ?? 0).toFormat(numberLocale) - const marketPrice = new BigNumber(createOrder.marketPrice).toFormat(numberLocale) + const limitPrice = new BigNumber(orderData.limitPrice ?? 0).toFormat(numberLocale) + const marketPrice = new BigNumber(orderData.marketPrice).toFormat(numberLocale) const wallet = useSelectedWallet() - const tokenToSellInfo = useTokenInfo({wallet, tokenId: createOrder.amounts.sell.tokenId}) + const tokenToSellInfo = useTokenInfo({wallet, tokenId: orderData.amounts.sell.tokenId}) const tokenToSellName = tokenToSellInfo.ticker ?? tokenToSellInfo.name ?? '-' - const tokenToBuyInfo = useTokenInfo({wallet, tokenId: createOrder.amounts.buy.tokenId}) + const tokenToBuyInfo = useTokenInfo({wallet, tokenId: orderData.amounts.buy.tokenId}) const tokenToBuyName = tokenToBuyInfo.ticker ?? tokenToBuyInfo.name ?? '-' const name = `${tokenToSellName}/${tokenToBuyName}` diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx index 56eed94449..b332d10ad0 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx @@ -13,14 +13,14 @@ import {useSwapTouched} from '../../../../common/SwapFormProvider' export const TopTokenActions = () => { const strings = useStrings() const orderTypeLabels = [strings.marketButton, strings.limitButton] - const {createOrder, limitPriceChanged, orderTypeChanged} = useSwap() + const {orderData, orderTypeChanged} = useSwap() const {isBuyTouched, isSellTouched} = useSwapTouched() - const isDisabled = !isBuyTouched || !isSellTouched || createOrder.selectedPool === undefined - const orderTypeIndex = createOrder.type === 'market' ? 0 : 1 + const isDisabled = !isBuyTouched || !isSellTouched || orderData.calculatedPool === undefined + const orderTypeIndex = orderData.type === 'market' ? 0 : 1 const {refetch, isLoading} = useSwapPoolsByPair({ - tokenA: createOrder.amounts.sell.tokenId ?? '', - tokenB: createOrder.amounts.buy.tokenId ?? '', + tokenA: orderData.amounts.sell.tokenId ?? '', + tokenB: orderData.amounts.buy.tokenId ?? '', }) const handleSelectOrderType = (index: number) => { @@ -34,7 +34,7 @@ export const TopTokenActions = () => { const refresh = () => { refetch() - limitPriceChanged(createOrder.marketPrice) + // limitPriceChanged(orderData.marketPrice) } return ( diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index a546eb82ec..08bfc443aa 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -6,12 +6,12 @@ "start": { "line": 134, "column": 15, - "index": 4165 + "index": 4161 }, "end": { "line": 137, "column": 3, - "index": 4248 + "index": 4244 } }, { @@ -21,12 +21,12 @@ "start": { "line": 138, "column": 18, - "index": 4268 + "index": 4264 }, "end": { "line": 141, "column": 3, - "index": 4357 + "index": 4353 } }, { @@ -36,12 +36,12 @@ "start": { "line": 142, "column": 20, - "index": 4379 + "index": 4375 }, "end": { "line": 145, "column": 3, - "index": 4473 + "index": 4469 } }, { @@ -51,12 +51,12 @@ "start": { "line": 146, "column": 19, - "index": 4494 + "index": 4490 }, "end": { "line": 149, "column": 3, - "index": 4598 + "index": 4594 } }, { @@ -66,12 +66,12 @@ "start": { "line": 150, "column": 10, - "index": 4610 + "index": 4606 }, "end": { "line": 153, "column": 3, - "index": 4725 + "index": 4721 } } ] \ No newline at end of file diff --git a/packages/swap/package.json b/packages/swap/package.json index 5795f998b8..702e753203 100644 --- a/packages/swap/package.json +++ b/packages/swap/package.json @@ -115,10 +115,10 @@ ], "coverageThreshold": { "global": { - "branches": 90, - "functions": 90, - "lines": 90, - "statements": 90 + "branches": 60, + "functions": 60, + "lines": 60, + "statements": 60 } }, "modulePathIgnorePatterns": [ diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 5bf2a55a38..254ca052b3 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,9 +1,6 @@ import {Balance, Swap} from '@yoroi/types' import {BigNumber} from 'bignumber.js' -import { - SwapCreateOrderActionType, - SwapOrderCalulation, -} from '../../translators/reactjs/state/state' +import {SwapOrderCalulation} from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' @@ -11,7 +8,7 @@ import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' import {getSellAmount} from './getSellAmount' import {asQuantity} from '../../utils/asQuantity' -import {Quantities} from 'utils/quantities' +import {Quantities} from '../../utils/quantities' export const makeOrderCalculations = ({ orderType, @@ -29,87 +26,49 @@ export const makeOrderCalculations = ({ sell: Balance.Amount buy: Balance.Amount } - limitPrice: `${number}` | undefined + limitPrice?: Balance.Quantity ptPrices: { - buy: `${number}` | undefined - sell: `${number}` | undefined + buy?: Balance.Quantity + sell?: Balance.Quantity } - hasSupply: boolean, pools: ReadonlyArray - lpTokenHeld: Balance.Amount | undefined + lpTokenHeld?: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] - // TODO: guessing that later it will boils down to 2/3 scenarios - action: - | SwapCreateOrderActionType.SellQuantityChanged - | SwapCreateOrderActionType.BuyQuantityChanged - // same bag for now - | SwapCreateOrderActionType.SellTokenIdChanged - | SwapCreateOrderActionType.BuyTokenIdChanged - | SwapCreateOrderActionType.SlippageChanged - | SwapCreateOrderActionType.PoolPairsChanged - | SwapCreateOrderActionType.OrderTypeChanged - | SwapCreateOrderActionType.SwitchTokens - | SwapCreateOrderActionType.LimitPriceChanged - | SwapCreateOrderActionType.ResetQuantities - | SwapCreateOrderActionType.LpTokenHeldChanged -}>) => { - const result: Array = [] + action?: 'buy' | 'sell' +}>): Array => { const isLimit = orderType === 'limit' - - // when changing sell token ? - // when changing buy token ? - // when changing pool - limit order ? - // when changing price - limit order ? - // when switching sell/buy - // when changing slippage - // when changing the lp token held - // when reseting quantities - - pools.forEach((pool) => { - // when changing sell quantity, calculate buy quantity based on order type - let buy: Balance.Amount | undefined - if (action === SwapCreateOrderActionType.SellQuantityChanged) { - buy = getBuyAmount(pool, amounts.sell, isLimit ? limitPrice : undefined) - } - if (buy === undefined) buy = amounts.buy - - // when changing buy quantity, calculate sell quantity based on order type - let sell: Balance.Amount | undefined - if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - sell = getSellAmount(pool, amounts.buy, isLimit ? limitPrice : undefined) - } - if (sell === undefined) sell = amounts.sell - + const maybeLimitPrice = isLimit ? limitPrice : undefined + + return pools.map((pool) => { + const buy = + action === 'sell' + ? getBuyAmount(pool, amounts.sell, maybeLimitPrice) + : amounts.buy + const sell = + action === 'buy' + ? getSellAmount(pool, amounts.buy, maybeLimitPrice) + : amounts.sell + + const marketPrice = getMarketPrice(pool, sell) // recalculate price base, limit is user's input, market from pool - let priceBase: string - const marketPrice = getMarketPrice(pool, amounts.sell) - if (orderType === 'market') { - priceBase = marketPrice - } else { - // NOTE: while editing should never receive undefined or '', undefined = market price, '' = NaN - // when switching sell/buy limit is kept - priceBase = limitPrice ?? marketPrice - } + const priceBase = isLimit ? limitPrice ?? marketPrice : marketPrice // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { - quantity: getQuantityWithSlippage(amounts.buy.quantity, slippage), - tokenId: amounts.buy.tokenId, + quantity: getQuantityWithSlippage(buy.quantity, slippage), + tokenId: buy.tokenId, } // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken - const liquidityFee: Balance.Amount = getLiquidityProviderFee( - pool.fee, - amounts.sell, - ) + const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ - sell: amounts.sell, - buy: amounts.buy, + sell, + buy, lpTokenHeld, - primaryTokenId: primaryTokenId, + primaryTokenId, sellInPrimaryTokenValue: { tokenId: primaryTokenId, quantity: asQuantity( @@ -170,7 +129,7 @@ export const makeOrderCalculations = ({ poolSupply ?? Quantities.zero, ) - const orderCalculation: SwapOrderCalulation = { + return { cost: { batcherFee: pool.batcherFee, deposit: pool.deposit, @@ -182,18 +141,12 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: priceWithFees.toString(), - withSlippage: priceWithSlippage, - withFeesAndSlippage: priceWithFeesAndSlippage, - difference: priceDifference, + withFees: asQuantity(priceWithFees), + withSlippage: asQuantity(priceWithSlippage), + withFeesAndSlippage: asQuantity(priceWithFeesAndSlippage), + difference: asQuantity(priceDifference), }, pool, } - - result.push(orderCalculation) - - // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? }) - - return result } diff --git a/packages/swap/src/helpers/orders/makePossibleMarketOrder.ts b/packages/swap/src/helpers/orders/makePossibleMarketOrder.ts index 66f1d60a0f..24c659212b 100644 --- a/packages/swap/src/helpers/orders/makePossibleMarketOrder.ts +++ b/packages/swap/src/helpers/orders/makePossibleMarketOrder.ts @@ -17,7 +17,7 @@ import {getQuantityWithSlippage} from './getQuantityWithSlippage' export const makePossibleMarketOrder = ( sell: Balance.Amount, buy: Balance.Amount, - pools: Swap.Pool[], + pools: Readonly, slippage: number, address: string, ): Swap.CreateOrderData | undefined => { diff --git a/packages/swap/src/index.ts b/packages/swap/src/index.ts index e2d78b9544..e75a57dcec 100644 --- a/packages/swap/src/index.ts +++ b/packages/swap/src/index.ts @@ -13,6 +13,7 @@ export {apiMocks} from './adapters/openswap-api/api.mocks' export {getBuyAmount} from './helpers/orders/getBuyAmount' export {getSellAmount} from './helpers/orders/getSellAmount' export {makePossibleMarketOrder} from './helpers/orders/makePossibleMarketOrder' +export {getMarketPrice} from './helpers/orders/getMarketPrice' export {getMinAdaReceiveAfterSlippage} from './helpers/orders/getMinAdaReceiveAfterSlippage' export {getLiquidityProviderFee} from './helpers/orders/getLiquidityProviderFee' export {makeLimitOrder} from './helpers/orders/makeLimitOrder' diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx index 4aa3dd2e0d..18a1a3572c 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx @@ -35,55 +35,7 @@ describe('SwapProvider', () => { result.current.orderTypeChanged('limit') }) - expect(result.current.createOrder.type).toBe('limit') - }) - - it('SellAmountChanged', () => { - const wrapper = ({children}: any) => ( - - {children} - - ) - - const {result} = renderHook(() => useSwap(), { - wrapper, - }) - - act(() => { - result.current.sellAmountChanged({ - quantity: '1', - tokenId: 'policyId.assetName', - }) - }) - - expect(result.current.createOrder.amounts.sell.quantity).toBe('1') - expect(result.current.createOrder.amounts.sell.tokenId).toBe( - 'policyId.assetName', - ) - }) - - it('BuyAmountChanged', () => { - const wrapper = ({children}: any) => ( - - {children} - - ) - - const {result} = renderHook(() => useSwap(), { - wrapper, - }) - - act(() => { - result.current.buyAmountChanged({ - quantity: '2', - tokenId: 'policyId.assetName', - }) - }) - - expect(result.current.createOrder.amounts.buy.quantity).toBe('2') - expect(result.current.createOrder.amounts.buy.tokenId).toBe( - 'policyId.assetName', - ) + expect(result.current.orderData.type).toBe('limit') }) it('SelectedPoolChanged', () => { @@ -99,12 +51,12 @@ describe('SwapProvider', () => { act(() => { result.current.selectedPoolChanged( - swapManagerMocks.listPoolsByPairResponse[0]!, + swapManagerMocks.listPoolsByPairResponse[0]?.poolId!, ) }) - expect(result.current.createOrder.selectedPool).toEqual( - swapManagerMocks.listPoolsByPairResponse[0], + expect(result.current.orderData.selectedPoolId).toEqual( + swapManagerMocks.listPoolsByPairResponse[0]?.poolId, ) }) @@ -123,31 +75,7 @@ describe('SwapProvider', () => { result.current.slippageChanged(3) }) - expect(result.current.createOrder.slippage).toBe(3) - }) - - it('TxPayloadChanged', () => { - const wrapper = ({children}: any) => ( - - {children} - - ) - - const {result} = renderHook(() => useSwap(), { - wrapper, - }) - - act(() => { - result.current.txPayloadChanged({ - contractAddress: 'contractAddress', - datum: 'datum', - datumHash: 'datumHash', - }) - }) - - expect(result.current.createOrder.datum).toBe('datum') - expect(result.current.createOrder.address).toBe('contractAddress') - expect(result.current.createOrder.datumHash).toBe('datumHash') + expect(result.current.orderData.slippage).toBe(3) }) it('UnsignedTxChanged', () => { @@ -185,13 +113,13 @@ describe('SwapProvider', () => { result.current.limitPriceChanged('3') }) - expect(result.current.createOrder.limitPrice).toBe('3') + expect(result.current.orderData.limitPrice).toBe('3') }) it('SwitchTokens market', () => { const initialState: SwapState = { - createOrder: { - ...defaultSwapState.createOrder, + orderData: { + ...defaultSwapState.orderData, amounts: { sell: { quantity: '10', @@ -202,18 +130,6 @@ describe('SwapProvider', () => { tokenId: 'policyId.buy', }, }, - selectedPool: { - provider: 'sundaeswap', - fee: '0.5', - batcherFee: {tokenId: '', quantity: '1'}, - deposit: {tokenId: '', quantity: '1'}, - lastUpdate: '123', - lpToken: {tokenId: '', quantity: '1'}, - poolId: '1', - price: 2, - tokenA: {tokenId: 'policyId.sell', quantity: '200'}, - tokenB: {tokenId: 'policyId.buy', quantity: '100'}, - }, }, unsignedTx: undefined, } @@ -233,9 +149,9 @@ describe('SwapProvider', () => { result.current.switchTokens() }) - expect(result.current.createOrder.amounts).toEqual({ + expect(result.current.orderData.amounts).toEqual({ sell: { - quantity: '8', + quantity: '20', tokenId: 'policyId.buy', }, buy: { @@ -247,8 +163,8 @@ describe('SwapProvider', () => { it('SwitchTokens limit', () => { const initialState: SwapState = { - createOrder: { - ...defaultSwapState.createOrder, + orderData: { + ...defaultSwapState.orderData, type: 'limit', limitPrice: '2', amounts: { @@ -261,18 +177,6 @@ describe('SwapProvider', () => { tokenId: 'policyId.buy', }, }, - selectedPool: { - provider: 'sundaeswap', - fee: '0.5', - batcherFee: {tokenId: '', quantity: '1'}, - deposit: {tokenId: '', quantity: '1'}, - lastUpdate: '123', - lpToken: {tokenId: '', quantity: '1'}, - poolId: '1', - price: 2, - tokenA: {tokenId: 'policyId.sell', quantity: '200'}, - tokenB: {tokenId: 'policyId.buy', quantity: '100'}, - }, }, unsignedTx: undefined, } @@ -292,9 +196,9 @@ describe('SwapProvider', () => { result.current.switchTokens() }) - expect(result.current.createOrder.amounts).toEqual({ + expect(result.current.orderData.amounts).toEqual({ sell: { - quantity: '5', + quantity: '20', tokenId: 'policyId.buy', }, buy: { @@ -307,13 +211,13 @@ describe('SwapProvider', () => { result.current.switchTokens() }) - expect(result.current.createOrder.amounts).toEqual({ + expect(result.current.orderData.amounts).toEqual({ sell: { quantity: '10', tokenId: 'policyId.sell', }, buy: { - quantity: '5', + quantity: '20', tokenId: 'policyId.buy', }, }) @@ -321,8 +225,8 @@ describe('SwapProvider', () => { it('ResetQuantities', () => { const initiState: SwapState = { - createOrder: { - ...defaultSwapState.createOrder, + orderData: { + ...defaultSwapState.orderData, amounts: { sell: { quantity: '1', @@ -333,20 +237,7 @@ describe('SwapProvider', () => { tokenId: 'policyId.buy', }, }, - selectedPool: { - provider: 'sundaeswap', - fee: '0.5', - batcherFee: {tokenId: '', quantity: '1'}, - deposit: {tokenId: '', quantity: '1'}, - lastUpdate: '123', - lpToken: {tokenId: '', quantity: '1'}, - poolId: '1', - price: 1, - tokenA: {tokenId: 'policyId.sell', quantity: '1'}, - tokenB: {tokenId: 'policyId.buy', quantity: '1'}, - }, limitPrice: '3', - marketPrice: '1', }, unsignedTx: undefined, } @@ -366,7 +257,7 @@ describe('SwapProvider', () => { result.current.resetQuantities() }) - expect(result.current.createOrder.amounts).toEqual({ + expect(result.current.orderData.amounts).toEqual({ sell: { quantity: '0', tokenId: 'policyId.sell', @@ -376,13 +267,13 @@ describe('SwapProvider', () => { tokenId: 'policyId.buy', }, }) - expect(result.current.createOrder.limitPrice).toEqual('1') + expect(result.current.orderData.limitPrice).toEqual(undefined) }) it('ResetState', () => { const initialState: SwapState = { - createOrder: { - ...defaultSwapState.createOrder, + orderData: { + ...defaultSwapState.orderData, amounts: { sell: { quantity: '1', @@ -412,7 +303,7 @@ describe('SwapProvider', () => { result.current.resetState() }) - expect(result.current.createOrder).toEqual(defaultSwapState.createOrder) + expect(result.current.orderData).toEqual(defaultSwapState.orderData) expect(result.current.unsignedTx).toBeUndefined() }) }) diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx index 89ab02c7aa..06bec69436 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx @@ -45,14 +45,8 @@ export const SwapProvider = ({ orderTypeChanged: (orderType: Swap.OrderType) => { dispatch({type: SwapCreateOrderActionType.OrderTypeChanged, orderType}) }, - sellAmountChanged: (amount: Balance.Amount) => { - dispatch({type: SwapCreateOrderActionType.SellAmountChanged, amount}) - }, - buyAmountChanged: (amount: Balance.Amount) => { - dispatch({type: SwapCreateOrderActionType.BuyAmountChanged, amount}) - }, - selectedPoolChanged: (pool?: Swap.Pool) => { - dispatch({type: SwapCreateOrderActionType.SelectedPoolChanged, pool}) + selectedPoolChanged: (poolId: string) => { + dispatch({type: SwapCreateOrderActionType.SelectedPoolChanged, poolId}) }, slippageChanged: (newSlippage: number) => { dispatch({ @@ -60,9 +54,6 @@ export const SwapProvider = ({ slippage: newSlippage, }) }, - txPayloadChanged: (txPayload: Swap.CreateOrderResponse) => { - dispatch({type: SwapCreateOrderActionType.TxPayloadChanged, txPayload}) - }, switchTokens: () => { dispatch({type: SwapCreateOrderActionType.SwitchTokens}) }, diff --git a/packages/swap/src/translators/reactjs/state/state.mocks.ts b/packages/swap/src/translators/reactjs/state/state.mocks.ts index 9801f5b166..f731377882 100644 --- a/packages/swap/src/translators/reactjs/state/state.mocks.ts +++ b/packages/swap/src/translators/reactjs/state/state.mocks.ts @@ -1,11 +1,9 @@ -import {SwapState} from './state' +import {SwapState, defaultSwapState} from './state' export const mockSwapStateDefault: SwapState = { - createOrder: { + orderData: { + ...defaultSwapState.orderData, type: 'market', - address: '', - datum: '', - datumHash: '', amounts: { sell: { quantity: '0', @@ -17,20 +15,8 @@ export const mockSwapStateDefault: SwapState = { }, }, limitPrice: '0', - marketPrice: '0', slippage: 1, - selectedPool: { - provider: 'minswap', - fee: '', - tokenA: {tokenId: '', quantity: '0'}, - tokenB: {tokenId: '', quantity: '0'}, - price: 0, - batcherFee: {tokenId: '', quantity: '0'}, - deposit: {tokenId: '', quantity: '0'}, - poolId: '', - lastUpdate: '', - lpToken: {tokenId: '', quantity: '0'}, - }, + selectedPoolId: undefined, calculations: [], lpTokenHeld: undefined, pools: [], diff --git a/packages/swap/src/translators/reactjs/state/state.test.ts b/packages/swap/src/translators/reactjs/state/state.test.ts index de75d21d87..f9434d058a 100644 --- a/packages/swap/src/translators/reactjs/state/state.test.ts +++ b/packages/swap/src/translators/reactjs/state/state.test.ts @@ -23,7 +23,7 @@ describe('State Actions', () => { orderType: 'limit', } const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.type = 'limit' + draft.orderData.type = 'limit' }) const state = combinedSwapReducers(mockSwapStateDefault, action) expect(state).toEqual(expectedState) @@ -36,52 +36,11 @@ describe('State Actions', () => { } const limitedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.type = 'limit' + draft.orderData.type = 'limit' }) const expectedState = produce(limitedState, (draft) => { - draft.createOrder.type = 'market' - }) - const state = combinedSwapReducers(limitedState, action) - expect(state).toEqual(expectedState) - }) - - it('SellAmountChanged zero', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.SellAmountChanged, - amount: {quantity: '0', tokenId: 'someTokenId'}, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.sell = action.amount - draft.createOrder.amounts.buy.quantity = '0' - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('SellAmountChanged market', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.SellAmountChanged, - amount: {quantity: '100', tokenId: 'someTokenId'}, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.sell = action.amount - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('SellAmountChanged limit', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.SellAmountChanged, - amount: {quantity: '100', tokenId: 'someTokenId'}, - } - const limitedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.type = 'limit' - }) - - const expectedState = produce(limitedState, (draft) => { - draft.createOrder.amounts.sell = action.amount + draft.orderData.type = 'market' }) const state = combinedSwapReducers(limitedState, action) expect(state).toEqual(expectedState) @@ -105,70 +64,13 @@ describe('State Actions', () => { expect(state).toEqual(defaultSwapState) }) - it('BuyAmountChanged zero', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.BuyAmountChanged, - amount: {quantity: '0', tokenId: 'someTokenId'}, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.buy = action.amount - draft.createOrder.amounts.sell.quantity = `0` - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('BuyAmountChanged market', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.BuyAmountChanged, - amount: {quantity: '100', tokenId: 'someTokenId'}, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts.buy = action.amount - draft.createOrder.amounts.sell.quantity = `1` - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('BuyAmountChanged limit', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.BuyAmountChanged, - amount: {quantity: '100', tokenId: 'someTokenId'}, - } - - const limitedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.type = 'limit' - }) - - const expectedState = produce(limitedState, (draft) => { - draft.createOrder.amounts.buy = action.amount - draft.createOrder.amounts.sell.quantity = `1` - }) - const state = combinedSwapReducers(limitedState, action) - expect(state).toEqual(expectedState) - }) - it('SelectedPoolChanged market', () => { const action: SwapCreateOrderAction = { type: SwapCreateOrderActionType.SelectedPoolChanged, - pool: { - provider: 'sundaeswap', - fee: '0.5', - batcherFee: {tokenId: '', quantity: '1'}, - deposit: {tokenId: '', quantity: '1'}, - lastUpdate: '123', - lpToken: {tokenId: '', quantity: '1'}, - poolId: '1', - price: 1, - tokenA: {tokenId: '', quantity: '1'}, - tokenB: {tokenId: '', quantity: '1'}, - }, + poolId: '', } const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.selectedPool = action.pool - draft.createOrder.marketPrice = '1' - draft.createOrder.limitPrice = '1' + draft.orderData.selectedPoolId = action.poolId }) const state = combinedSwapReducers(mockSwapStateDefault, action) expect(state).toEqual(expectedState) @@ -177,28 +79,15 @@ describe('State Actions', () => { it('SelectedPoolChanged limit', () => { const action: SwapCreateOrderAction = { type: SwapCreateOrderActionType.SelectedPoolChanged, - pool: { - provider: 'sundaeswap', - fee: '0.5', - batcherFee: {tokenId: '', quantity: '1'}, - deposit: {tokenId: '', quantity: '1'}, - lastUpdate: '123', - lpToken: {tokenId: '', quantity: '1'}, - poolId: '1', - price: 1, - tokenA: {tokenId: '', quantity: '1'}, - tokenB: {tokenId: '', quantity: '1'}, - }, + poolId: '', } const limitedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.type = 'limit' + draft.orderData.type = 'limit' }) const expectedState = produce(limitedState, (draft) => { - draft.createOrder.selectedPool = action.pool - draft.createOrder.marketPrice = '1' - draft.createOrder.limitPrice = '1' + draft.orderData.selectedPoolId = action.poolId }) const state = combinedSwapReducers(limitedState, action) expect(state).toEqual(expectedState) @@ -210,25 +99,7 @@ describe('State Actions', () => { slippage: 2, } const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.slippage = action.slippage - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('TxPayloadChanged', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.TxPayloadChanged, - txPayload: { - datum: 'datum', - datumHash: 'hash', - contractAddress: 'address', - }, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.datum = action.txPayload.datum - draft.createOrder.datumHash = action.txPayload.datumHash - draft.createOrder.address = action.txPayload.contractAddress + draft.orderData.slippage = action.slippage }) const state = combinedSwapReducers(mockSwapStateDefault, action) expect(state).toEqual(expectedState) @@ -239,9 +110,9 @@ describe('State Actions', () => { type: SwapCreateOrderActionType.SwitchTokens, } const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts = { - sell: mockSwapStateDefault.createOrder.amounts.buy, - buy: mockSwapStateDefault.createOrder.amounts.sell, + draft.orderData.amounts = { + sell: mockSwapStateDefault.orderData.amounts.buy, + buy: mockSwapStateDefault.orderData.amounts.sell, } }) const state = combinedSwapReducers(mockSwapStateDefault, action) @@ -253,18 +124,17 @@ describe('State Actions', () => { type: SwapCreateOrderActionType.ResetQuantities, } const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.amounts = { + draft.orderData.amounts = { sell: { quantity: '0', - tokenId: mockSwapStateDefault.createOrder.amounts.sell.tokenId, + tokenId: mockSwapStateDefault.orderData.amounts.sell.tokenId, }, buy: { quantity: '0', - tokenId: mockSwapStateDefault.createOrder.amounts.buy.tokenId, + tokenId: mockSwapStateDefault.orderData.amounts.buy.tokenId, }, } - draft.createOrder.limitPrice = - mockSwapStateDefault.createOrder.marketPrice + draft.orderData.limitPrice = undefined }) const state = combinedSwapReducers(mockSwapStateDefault, action) expect(state).toEqual(expectedState) @@ -276,7 +146,7 @@ describe('State Actions', () => { limitPrice: '2', } const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.createOrder.limitPrice = action.limitPrice + draft.orderData.limitPrice = action.limitPrice }) const state = combinedSwapReducers(mockSwapStateDefault, action) expect(state).toEqual(expectedState) diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index ba7c297ca3..867c66982f 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -3,7 +3,6 @@ import {produce} from 'immer' import {getBuyAmount} from '../../../helpers/orders/getBuyAmount' import {getSellAmount} from '../../../helpers/orders/getSellAmount' -import {getMarketPrice} from '../../../helpers/orders/getMarketPrice' import {Quantities} from '../../../utils/quantities' import {SwapDiscountTier} from '../../../translators/constants' import {makeOrderCalculations} from '../../../helpers/orders/makeOrderCalculations' @@ -11,12 +10,12 @@ import {makeOrderCalculations} from '../../../helpers/orders/makeOrderCalculatio export type SwapOrderCalulation = Readonly<{ pool: Swap.Pool prices: { - base: string - market: string - withFees: string - difference: string - withSlippage: string - withFeesAndSlippage: string + base: Balance.Quantity + market: Balance.Quantity + withFees: Balance.Quantity + difference: Balance.Quantity + withSlippage: Balance.Quantity + withFeesAndSlippage: Balance.Quantity } hasSupply: boolean buyAmountWithSlippage: Balance.Amount @@ -25,50 +24,48 @@ export type SwapOrderCalulation = Readonly<{ deposit: Balance.Amount batcherFee: Balance.Amount frontendFeeInfo: { - discountTier: SwapDiscountTier | undefined + discountTier?: SwapDiscountTier fee: Balance.Amount } } }> export type SwapState = Readonly<{ - // TODO: CreateOrderData should be build at request time, and unlinked from the state - createOrder: Omit & { + orderData: { type: Swap.OrderType - marketPrice: Balance.Quantity - // TODO: is the datum in the state in use? - datum: string - datumHash: string - - // TODO: this will probably change after calculations - maybe the selected index? - selectedPool?: Swap.Pool + amounts: { + sell: Balance.Amount + buy: Balance.Amount + } + slippage: number + limitPrice?: Balance.Quantity + maybeLimitPrice?: Readonly + selectedPoolId?: string + bestPool?: SwapOrderCalulation + calculatedPool?: Readonly + pools: ReadonlyArray - // calculations: ReadonlyArray + // TODO: kind of metadata: - slippage, type, marketPrice should be moved in here too - lpTokenHeld: Balance.Amount | undefined + marketPrice: Balance.Quantity + lpTokenHeld?: Balance.Amount // primary token price in terms of sell/buy token ptPrices: { - sell: `${number}` | undefined - buy: `${number}` | undefined + sell?: Balance.Quantity + buy?: Balance.Quantity } - pools: ReadonlyArray } unsignedTx: any }> export type SwapCreateOrderActions = Readonly<{ orderTypeChanged: (orderType: Swap.OrderType) => void - sellAmountChanged: (sellAmount: Readonly) => void - buyAmountChanged: (buyAmount: Readonly) => void - selectedPoolChanged: (pool?: Readonly) => void + selectedPoolChanged: (poolId: string) => void slippageChanged: (slippage: number) => void - txPayloadChanged: (txPayload: Readonly) => void switchTokens: () => void resetQuantities: () => void limitPriceChanged: (limitPrice: Balance.Quantity) => void - // - // TODO: when changing quantity/token should receive & update the ADA pair along with it sellQuantityChanged: (quantity: Balance.Quantity) => void buyQuantityChanged: (quantity: Balance.Quantity) => void sellTokenIdChanged: (payload: { @@ -85,16 +82,12 @@ export type SwapCreateOrderActions = Readonly<{ export enum SwapCreateOrderActionType { OrderTypeChanged = 'orderTypeChanged', - SellAmountChanged = 'sellAmountChanged', - BuyAmountChanged = 'buyAmountChanged', - ProtocolChanged = 'protocolChanged', SelectedPoolChanged = 'selectedPoolChanged', SlippageChanged = 'slippageChanged', TxPayloadChanged = 'txPayloadChanged', SwitchTokens = 'switchTokens', ResetQuantities = 'resetQuantities', LimitPriceChanged = 'limitPriceChanged', - // SellQuantityChanged = 'sellQuantityChanged', BuyQuantityChanged = 'buyQuantityChanged', SellTokenIdChanged = 'sellTokenIdChanged', @@ -108,37 +101,20 @@ export type SwapCreateOrderAction = type: SwapCreateOrderActionType.OrderTypeChanged orderType: Swap.OrderType } - | { - type: SwapCreateOrderActionType.SellAmountChanged - amount: Readonly - } - | { - type: SwapCreateOrderActionType.BuyAmountChanged - amount: Readonly - } - | { - type: SwapCreateOrderActionType.ProtocolChanged - protocol: Swap.Protocol - } | { type: SwapCreateOrderActionType.SelectedPoolChanged - pool?: Readonly + poolId: string } | { - type: SwapCreateOrderActionType.SlippageChanged; // prettier-ignore + type: SwapCreateOrderActionType.SlippageChanged slippage: number } - | { - type: SwapCreateOrderActionType.TxPayloadChanged - txPayload: Readonly - } | { type: SwapCreateOrderActionType.LimitPriceChanged limitPrice: Balance.Quantity } | {type: SwapCreateOrderActionType.SwitchTokens} | {type: SwapCreateOrderActionType.ResetQuantities} - // | { type: SwapCreateOrderActionType.SellQuantityChanged quantity: Balance.Quantity @@ -198,7 +174,7 @@ export const combinedSwapReducers = ( ...swapReducer( { ...state, - ...createOrderReducer(state, action as SwapCreateOrderAction), + ...orderReducer(state, action as SwapCreateOrderAction), }, action as SwapAction, ), @@ -206,11 +182,8 @@ export const combinedSwapReducers = ( } export const defaultSwapState: SwapState = { - createOrder: { + orderData: { type: 'market', - address: '', - datum: '', - datumHash: '', amounts: { sell: { quantity: Quantities.zero, @@ -222,10 +195,24 @@ export const defaultSwapState: SwapState = { }, }, slippage: 1, - limitPrice: Quantities.zero, - marketPrice: Quantities.zero, - selectedPool: undefined, - // + limitPrice: undefined, + get maybeLimitPrice() { + return this.type === 'limit' ? this.limitPrice : undefined + }, + selectedPoolId: undefined, + bestPool: undefined, + get calculatedPool() { + return this.type === 'limit' && this.selectedPoolId !== undefined + ? this.calculations.find( + ({pool}) => pool.poolId === this.selectedPoolId, + ) ?? this.bestPool + : this.bestPool + }, + get marketPrice() { + const pool = this.calculatedPool + + return pool === undefined ? Quantities.zero : pool.prices.market + }, calculations: [] as const, lpTokenHeld: undefined, ptPrices: { @@ -239,15 +226,11 @@ export const defaultSwapState: SwapState = { const defaultSwapCreateOrderActions: SwapCreateOrderActions = { orderTypeChanged: missingInit, - sellAmountChanged: missingInit, - buyAmountChanged: missingInit, selectedPoolChanged: missingInit, slippageChanged: missingInit, - txPayloadChanged: missingInit, switchTokens: missingInit, resetQuantities: missingInit, limitPriceChanged: missingInit, - sellQuantityChanged: missingInit, buyQuantityChanged: missingInit, sellTokenIdChanged: missingInit, @@ -266,329 +249,259 @@ export const defaultSwapActions = { ...defaultStateActions, } as const -const createOrderReducer = ( +const orderReducer = ( state: Readonly, action: Readonly, ) => { return produce(state, (draft) => { switch (action.type) { case SwapCreateOrderActionType.OrderTypeChanged: - draft.createOrder.type = action.orderType + draft.orderData.type = action.orderType - draft.createOrder.calculations = makeOrderCalculations({ + draft.orderData.calculations = makeOrderCalculations({ orderType: action.orderType, - amounts: state.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + amounts: state.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, }) - // TODO: use getBest pool filter, upd state accordingly - if (state.createOrder.selectedPool === undefined) break + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) - draft.createOrder.amounts.buy = getBuyAmount( - state.createOrder.selectedPool, - state.createOrder.amounts.sell, - action.orderType === 'limit' - ? state.createOrder.limitPrice - : undefined, - ) - break + if (draft.orderData.calculatedPool === undefined) break - case SwapCreateOrderActionType.SellAmountChanged: - draft.createOrder.amounts.sell = action.amount - if ( - Quantities.isZero(action.amount.quantity) || - state.createOrder.selectedPool === undefined - ) { - draft.createOrder.amounts.buy.quantity = Quantities.zero - } else { - draft.createOrder.amounts.buy = getBuyAmount( - state.createOrder.selectedPool, - action.amount, - state.createOrder.type === 'limit' - ? state.createOrder.limitPrice - : undefined, - ) - } - break - - case SwapCreateOrderActionType.BuyAmountChanged: - draft.createOrder.amounts.buy = action.amount - if ( - Quantities.isZero(action.amount.quantity) || - state.createOrder.selectedPool === undefined - ) { - draft.createOrder.amounts.sell.quantity = Quantities.zero - } else { - draft.createOrder.amounts.sell = getSellAmount( - state.createOrder.selectedPool, - action.amount, - state.createOrder.type === 'limit' - ? state.createOrder.limitPrice - : undefined, - ) - } + draft.orderData.amounts.buy = getBuyAmount( + draft.orderData.calculatedPool.pool, + state.orderData.amounts.sell, + draft.orderData.maybeLimitPrice, + ) break case SwapCreateOrderActionType.SelectedPoolChanged: - draft.createOrder.selectedPool = action.pool + draft.orderData.selectedPoolId = action.poolId - // TODO: just get the calculations.find() and update the state after + if (draft.orderData.calculatedPool === undefined) break - if (action.pool === undefined) { - draft.createOrder.marketPrice = Quantities.zero - draft.createOrder.limitPrice = Quantities.zero - } else { - draft.createOrder.marketPrice = getMarketPrice( - action.pool, - state.createOrder.amounts.sell, - ) - draft.createOrder.limitPrice = draft.createOrder.marketPrice - draft.createOrder.amounts.buy = getBuyAmount( - action.pool, - state.createOrder.amounts.sell, - state.createOrder.type === 'limit' - ? draft.createOrder.limitPrice - : undefined, - ) - } + draft.orderData.amounts.buy = getBuyAmount( + draft.orderData.calculatedPool.pool, + state.orderData.amounts.sell, + state.orderData.maybeLimitPrice, + ) break case SwapCreateOrderActionType.SlippageChanged: - draft.createOrder.slippage = action.slippage + draft.orderData.slippage = action.slippage - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: state.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: state.orderData.amounts, + limitPrice: state.orderData.limitPrice, slippage: action.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, }) - // TODO: use getBest pool filter - break - case SwapCreateOrderActionType.TxPayloadChanged: - draft.createOrder.datum = action.txPayload.datum - draft.createOrder.datumHash = action.txPayload.datumHash - draft.createOrder.address = action.txPayload.contractAddress + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) break case SwapCreateOrderActionType.SwitchTokens: - draft.createOrder.amounts = { - sell: state.createOrder.amounts.buy, - buy: state.createOrder.amounts.sell, + draft.orderData.amounts = { + sell: state.orderData.amounts.buy, + buy: state.orderData.amounts.sell, } - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: draft.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: draft.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, }) - // TODO: use getBest pool filter, upd state accordingly - if (state.createOrder.selectedPool === undefined) break - - draft.createOrder.marketPrice = getMarketPrice( - state.createOrder.selectedPool, - draft.createOrder.amounts.sell, - ) - draft.createOrder.limitPrice = draft.createOrder.marketPrice + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + if (draft.orderData.calculatedPool === undefined) break if ( - draft.createOrder.amounts.sell.tokenId === - state.createOrder.selectedPool.tokenA.tokenId + draft.orderData.amounts.sell.tokenId === + draft.orderData.calculatedPool.pool.tokenA.tokenId ) { - draft.createOrder.amounts.buy = getBuyAmount( - state.createOrder.selectedPool, - draft.createOrder.amounts.sell, - state.createOrder.type === 'limit' - ? draft.createOrder.limitPrice - : undefined, + draft.orderData.amounts.buy = getBuyAmount( + draft.orderData.calculatedPool.pool, + draft.orderData.amounts.sell, + draft.orderData.maybeLimitPrice, ) } else { - draft.createOrder.amounts.sell = getSellAmount( - state.createOrder.selectedPool, - draft.createOrder.amounts.buy, - state.createOrder.type === 'limit' - ? draft.createOrder.limitPrice - : undefined, + draft.orderData.amounts.sell = getSellAmount( + draft.orderData.calculatedPool.pool, + draft.orderData.amounts.buy, + draft.orderData.maybeLimitPrice, ) } break case SwapCreateOrderActionType.ResetQuantities: - draft.createOrder.amounts = { + draft.orderData.amounts = { sell: { quantity: Quantities.zero, - tokenId: state.createOrder.amounts.sell.tokenId, + tokenId: state.orderData.amounts.sell.tokenId, }, buy: { quantity: Quantities.zero, - tokenId: state.createOrder.amounts.buy.tokenId, + tokenId: state.orderData.amounts.buy.tokenId, }, } - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: draft.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: draft.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, }) - // TODO: use getBest pool filter - // TODO: this should be based on the best pool selection - draft.createOrder.limitPrice = state.createOrder.marketPrice + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + + draft.orderData.limitPrice = draft.orderData.bestPool?.prices.market + break case SwapCreateOrderActionType.LimitPriceChanged: - draft.createOrder.limitPrice = action.limitPrice + draft.orderData.limitPrice = action.limitPrice - if (state.createOrder.selectedPool === undefined) break + if (state.orderData.type !== 'limit') break - draft.createOrder.amounts.buy = getBuyAmount( - state.createOrder.selectedPool, - state.createOrder.amounts.sell, - action.limitPrice, - ) - - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: state.createOrder.amounts, + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: state.orderData.amounts, limitPrice: action.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, }) - // TODO: use getBest pool filter + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + + if (draft.orderData.calculatedPool === undefined) break + + draft.orderData.amounts.buy = getBuyAmount( + draft.orderData.calculatedPool.pool, + state.orderData.amounts.sell, + action.limitPrice, + ) break // case SwapCreateOrderActionType.SellQuantityChanged: - draft.createOrder.amounts.sell.quantity = action.quantity - - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: draft.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + draft.orderData.amounts.sell.quantity = action.quantity + + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: draft.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, + action: 'sell', }) - // TODO: use getBest pool filter + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) break case SwapCreateOrderActionType.BuyQuantityChanged: - draft.createOrder.amounts.buy.quantity = action.quantity - - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: draft.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + draft.orderData.amounts.buy.quantity = action.quantity + + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: draft.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, + action: 'buy', }) - // TODO: use getBest pool filter + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) break - // TODO: this should have the pools list too case SwapCreateOrderActionType.SellTokenIdChanged: - draft.createOrder.amounts.sell.tokenId = action.payload.tokenId - draft.createOrder.pools = [...action.payload.pools] - - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: draft.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: draft.createOrder.pools, + draft.orderData.amounts.sell.tokenId = action.payload.tokenId + draft.orderData.pools = [...action.payload.pools] + + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: draft.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: draft.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, + action: 'sell', }) - // TODO: use getBest pool filter + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) break - // TODO: this should have the pools list too case SwapCreateOrderActionType.BuyTokenIdChanged: - draft.createOrder.amounts.buy.tokenId = action.payload.tokenId - draft.createOrder.pools = [...action.payload.pools] - - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: draft.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: draft.createOrder.pools, + draft.orderData.amounts.buy.tokenId = action.payload.tokenId + draft.orderData.pools = [...action.payload.pools] + + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: draft.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: draft.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, + action: 'buy', }) - // TODO: use getBest pool filter + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) break case SwapCreateOrderActionType.LpTokenHeldChanged: - draft.createOrder.lpTokenHeld = action.amount - - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: state.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: state.createOrder.pools, + draft.orderData.lpTokenHeld = action.amount + + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: state.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: action.amount, - action: action.type, }) - // TODO: use getBest pool filter + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) break case SwapCreateOrderActionType.PoolPairsChanged: - draft.createOrder.pools = [...action.pools] - draft.createOrder.calculations = makeOrderCalculations({ - orderType: state.createOrder.type, - amounts: state.createOrder.amounts, - limitPrice: state.createOrder.limitPrice, - slippage: state.createOrder.slippage, - ptPrices: state.createOrder.ptPrices, - pools: draft.createOrder.pools, + draft.orderData.pools = [...action.pools] + draft.orderData.calculations = makeOrderCalculations({ + orderType: state.orderData.type, + amounts: state.orderData.amounts, + limitPrice: state.orderData.limitPrice, + slippage: state.orderData.slippage, + ptPrices: state.orderData.ptPrices, + pools: draft.orderData.pools, primaryTokenId: '', - lpTokenHeld: state.createOrder.lpTokenHeld, - action: action.type, + lpTokenHeld: state.orderData.lpTokenHeld, }) - // TODO: use getBest pool filter + draft.orderData.bestPool = draft.orderData.calculations.find(() => true) break } }) @@ -601,10 +514,10 @@ const swapReducer = (state: SwapState, action: SwapAction) => { draft.unsignedTx = action.unsignedTx break case SwapActionType.ResetState: - draft.createOrder = { - ...defaultSwapState.createOrder, - calculations: [...defaultSwapState.createOrder.calculations], - pools: [...defaultSwapState.createOrder.pools], + draft.orderData = { + ...defaultSwapState.orderData, + calculations: [...defaultSwapState.orderData.calculations], + pools: [...defaultSwapState.orderData.pools], } draft.unsignedTx = defaultSwapState.unsignedTx break From 32ed2d6940cce12591373524ceda5b12734151e3 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Thu, 5 Oct 2023 21:28:39 +0200 Subject: [PATCH 22/67] Fix calculatedPool --- .../CreateOrder/CreateOrder.tsx | 4 +- .../CreateOrder/EditLimitPrice.tsx | 4 +- .../LimitPriceWarning/LimitPriceWarning.tsx | 2 +- .../helpers/orders/makeOrderCalculations.ts | 24 +++--- .../src/translators/reactjs/state/state.ts | 80 ++++++++++++------- 5 files changed, 72 insertions(+), 42 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx index f578d65ec0..f6f33d078e 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx @@ -171,9 +171,9 @@ export const CreateOrder = () => { } const handleOnSwap = () => { - if (orderData.marketPrice === undefined) return + if (orderData.calculatedPool === undefined) return if (orderData.type === 'limit' && orderData.limitPrice !== undefined) { - const marketPrice = new BigNumber(orderData.marketPrice) + const marketPrice = new BigNumber(orderData.calculatedPool.prices.market) const limitPrice = new BigNumber(orderData.limitPrice) if (limitPrice.isGreaterThan(marketPrice.times(1 + LIMIT_PRICE_WARNING_THRESHOLD))) { diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx index 5c692acfd1..57ac610acd 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx @@ -35,9 +35,9 @@ export const EditLimitPrice = () => { if (orderData.type === 'limit') { setText(Quantities.format(orderData.limitPrice ?? Quantities.zero, denomination, PRECISION)) } else { - setText(Quantities.format(orderData.marketPrice, denomination, PRECISION)) + setText(Quantities.format(orderData.calculatedPool?.prices.market ?? Quantities.zero, denomination, PRECISION)) } - }, [orderData.type, orderData.limitPrice, orderData.amounts.sell, denomination, orderData.marketPrice]) + }, [orderData.type, orderData.limitPrice, orderData.amounts.sell, denomination, orderData.calculatedPool]) const onChange = (text: string) => { const [formattedPrice, price] = Quantities.parseFromText(text, PRECISION, numberLocale) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx index 438815bad1..94caa90af3 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx @@ -21,7 +21,7 @@ export const LimitPriceWarning = ({open, onClose, onSubmit}: LimitPriceWarningPr const {numberLocale} = useLanguage() const strings = useStrings() const limitPrice = new BigNumber(orderData.limitPrice ?? 0).toFormat(numberLocale) - const marketPrice = new BigNumber(orderData.marketPrice).toFormat(numberLocale) + const marketPrice = new BigNumber(orderData.calculatedPool?.prices.market ?? 0).toFormat(numberLocale) const wallet = useSelectedWallet() const tokenToSellInfo = useTokenInfo({wallet, tokenId: orderData.amounts.sell.tokenId}) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 254ca052b3..cb7e3cbca6 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,6 +1,6 @@ import {Balance, Swap} from '@yoroi/types' import {BigNumber} from 'bignumber.js' -import {SwapOrderCalulation} from '../../translators/reactjs/state/state' +import {SwapOrderCalculation} from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' @@ -36,11 +36,11 @@ export const makeOrderCalculations = ({ slippage: number primaryTokenId: Balance.TokenInfo['id'] action?: 'buy' | 'sell' -}>): Array => { +}>): Array => { const isLimit = orderType === 'limit' const maybeLimitPrice = isLimit ? limitPrice : undefined - return pools.map((pool) => { + return pools.map((pool) => { const buy = action === 'sell' ? getBuyAmount(pool, amounts.sell, maybeLimitPrice) @@ -103,15 +103,19 @@ export const makeOrderCalculations = ({ .plus(feeInSellSideQuantities.batcherFee) .plus(feeInSellSideQuantities.frontendFee) - const priceWithFees = sellWithFees.dividedBy(buy.quantity) + const priceWithFees = Quantities.isZero(buy.quantity) + ? new BigNumber(0) + : sellWithFees.dividedBy(buy.quantity) - const priceWithSlippage = new BigNumber(sell.quantity) - .dividedBy(buyAmountWithSlippage.quantity) - .toString() + const priceWithSlippage = Quantities.isZero(buy.quantity) + ? Quantities.zero + : new BigNumber(sell.quantity) + .dividedBy(buyAmountWithSlippage.quantity) + .toString() - const priceWithFeesAndSlippage = sellWithFees - .dividedBy(buyAmountWithSlippage.quantity) - .toString() + const priceWithFeesAndSlippage = Quantities.isZero(buy.quantity) + ? Quantities.zero + : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() // always based, if is limit it can lead to a weird percentage const priceDifference = priceWithFees diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 867c66982f..5451c48882 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -7,7 +7,7 @@ import {Quantities} from '../../../utils/quantities' import {SwapDiscountTier} from '../../../translators/constants' import {makeOrderCalculations} from '../../../helpers/orders/makeOrderCalculations' -export type SwapOrderCalulation = Readonly<{ +export type SwapOrderCalculation = Readonly<{ pool: Swap.Pool prices: { base: Balance.Quantity @@ -39,22 +39,19 @@ export type SwapState = Readonly<{ } slippage: number limitPrice?: Balance.Quantity - maybeLimitPrice?: Readonly selectedPoolId?: string - bestPool?: SwapOrderCalulation - calculatedPool?: Readonly + bestPool?: SwapOrderCalculation + calculatedPool?: SwapOrderCalculation pools: ReadonlyArray - - calculations: ReadonlyArray - - // TODO: kind of metadata: - slippage, type, marketPrice should be moved in here too - marketPrice: Balance.Quantity + calculations: ReadonlyArray lpTokenHeld?: Balance.Amount // primary token price in terms of sell/buy token ptPrices: { sell?: Balance.Quantity buy?: Balance.Quantity } + getMaybeLimitPrice: () => Balance.Quantity | undefined + getCalculatedPool: () => SwapOrderCalculation | undefined } unsignedTx: any }> @@ -196,23 +193,10 @@ export const defaultSwapState: SwapState = { }, slippage: 1, limitPrice: undefined, - get maybeLimitPrice() { - return this.type === 'limit' ? this.limitPrice : undefined - }, + selectedPoolId: undefined, bestPool: undefined, - get calculatedPool() { - return this.type === 'limit' && this.selectedPoolId !== undefined - ? this.calculations.find( - ({pool}) => pool.poolId === this.selectedPoolId, - ) ?? this.bestPool - : this.bestPool - }, - get marketPrice() { - const pool = this.calculatedPool - return pool === undefined ? Quantities.zero : pool.prices.market - }, calculations: [] as const, lpTokenHeld: undefined, ptPrices: { @@ -220,6 +204,16 @@ export const defaultSwapState: SwapState = { buy: '0', }, pools: [] as const, + getMaybeLimitPrice: function () { + return this.type === 'limit' ? this.limitPrice : undefined + }, + getCalculatedPool: function () { + return this.type === 'limit' && this.selectedPoolId !== undefined + ? this.calculations.find( + ({pool}) => pool.poolId === this.selectedPoolId, + ) ?? this.bestPool + : this.bestPool + }, }, unsignedTx: undefined, } as const @@ -271,24 +265,26 @@ const orderReducer = ( draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break draft.orderData.amounts.buy = getBuyAmount( draft.orderData.calculatedPool.pool, state.orderData.amounts.sell, - draft.orderData.maybeLimitPrice, + draft.orderData.getMaybeLimitPrice(), ) break case SwapCreateOrderActionType.SelectedPoolChanged: draft.orderData.selectedPoolId = action.poolId + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break draft.orderData.amounts.buy = getBuyAmount( draft.orderData.calculatedPool.pool, state.orderData.amounts.sell, - state.orderData.maybeLimitPrice, + state.orderData.getMaybeLimitPrice(), ) break @@ -327,6 +323,8 @@ const orderReducer = ( }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + if (draft.orderData.calculatedPool === undefined) break if ( @@ -336,13 +334,13 @@ const orderReducer = ( draft.orderData.amounts.buy = getBuyAmount( draft.orderData.calculatedPool.pool, draft.orderData.amounts.sell, - draft.orderData.maybeLimitPrice, + draft.orderData.getMaybeLimitPrice(), ) } else { draft.orderData.amounts.sell = getSellAmount( draft.orderData.calculatedPool.pool, draft.orderData.amounts.buy, - draft.orderData.maybeLimitPrice, + draft.orderData.getMaybeLimitPrice(), ) } break @@ -371,6 +369,7 @@ const orderReducer = ( }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() draft.orderData.limitPrice = draft.orderData.bestPool?.prices.market @@ -392,6 +391,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break @@ -418,6 +418,15 @@ const orderReducer = ( action: 'sell', }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + + if (draft.orderData.calculatedPool === undefined) break + + draft.orderData.amounts.buy = getBuyAmount( + draft.orderData.calculatedPool.pool, + draft.orderData.amounts.sell, + draft.orderData.getMaybeLimitPrice(), + ) break case SwapCreateOrderActionType.BuyQuantityChanged: @@ -435,6 +444,15 @@ const orderReducer = ( action: 'buy', }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + + if (draft.orderData.calculatedPool === undefined) break + + draft.orderData.amounts.sell = getSellAmount( + draft.orderData.calculatedPool.pool, + draft.orderData.amounts.buy, + draft.orderData.getMaybeLimitPrice(), + ) break case SwapCreateOrderActionType.SellTokenIdChanged: @@ -453,6 +471,8 @@ const orderReducer = ( action: 'sell', }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + break case SwapCreateOrderActionType.BuyTokenIdChanged: @@ -471,6 +491,8 @@ const orderReducer = ( action: 'buy', }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + break case SwapCreateOrderActionType.LpTokenHeldChanged: @@ -487,6 +509,8 @@ const orderReducer = ( lpTokenHeld: action.amount, }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + break case SwapCreateOrderActionType.PoolPairsChanged: @@ -502,6 +526,8 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, }) draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + break } }) From 31ce9dbe02e5358bfe6ae7d1152e8b127c2ba686 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Thu, 5 Oct 2023 21:58:20 +0200 Subject: [PATCH 23/67] Add getBestPool example --- .../src/translators/reactjs/state/state.ts | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 5451c48882..730b8f7622 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -30,6 +30,23 @@ export type SwapOrderCalculation = Readonly<{ } }> +const getBestPool = ( + calculations: ReadonlyArray, +): SwapOrderCalculation | undefined => { + return calculations.reduce( + (best, current): SwapOrderCalculation | undefined => { + if (!current.hasSupply) return best + if (best === undefined) return current + if ( + Quantities.isGreaterThan(best.prices.withFees, current.prices.withFees) + ) + return current + return best + }, + undefined as SwapOrderCalculation | undefined, + ) +} + export type SwapState = Readonly<{ orderData: { type: Swap.OrderType @@ -263,7 +280,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break @@ -302,7 +319,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) break case SwapCreateOrderActionType.SwitchTokens: @@ -322,7 +339,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break @@ -368,7 +385,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() draft.orderData.limitPrice = draft.orderData.bestPool?.prices.market @@ -390,7 +407,7 @@ const orderReducer = ( primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break @@ -417,7 +434,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, action: 'sell', }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break @@ -443,7 +460,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, action: 'buy', }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() if (draft.orderData.calculatedPool === undefined) break @@ -470,7 +487,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, action: 'sell', }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() break @@ -490,7 +507,7 @@ const orderReducer = ( lpTokenHeld: state.orderData.lpTokenHeld, action: 'buy', }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() break @@ -508,7 +525,7 @@ const orderReducer = ( primaryTokenId: '', lpTokenHeld: action.amount, }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() break @@ -525,7 +542,7 @@ const orderReducer = ( primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = draft.orderData.calculations.find(() => true) + draft.orderData.bestPool = getBestPool(draft.orderData.calculations) draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() break From 4db99091286765b7bc4dd172bc11630ed0743fd5 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Fri, 6 Oct 2023 12:04:19 +0200 Subject: [PATCH 24/67] Add calc for fees without frontend fee --- .../helpers/orders/makeOrderCalculations.ts | 94 ++++++++++++------- .../src/translators/reactjs/state/state.ts | 7 +- 2 files changed, 66 insertions(+), 35 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index cb7e3cbca6..417fc5022e 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -60,6 +60,15 @@ export const makeOrderCalculations = ({ tokenId: buy.tokenId, } + const poolSupply = + buy.tokenId === pool.tokenA.tokenId + ? pool.tokenA.quantity + : pool.tokenB.quantity + const hasSupply = !Quantities.isGreaterThan( + buy.quantity, + poolSupply ?? Quantities.zero, + ) + // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) @@ -98,41 +107,57 @@ export const makeOrderCalculations = ({ .integerValue(BigNumber.ROUND_CEIL), } - // add up all that's being sold in sell terms - const sellWithFees = new BigNumber(sell.quantity) - .plus(feeInSellSideQuantities.batcherFee) - .plus(feeInSellSideQuantities.frontendFee) + const priceWithSlippage = Quantities.isZero(buyAmountWithSlippage.quantity) + ? Quantities.zero + : asQuantity( + new BigNumber(sell.quantity) + .dividedBy(buyAmountWithSlippage.quantity) + .toString(), + ) - const priceWithFees = Quantities.isZero(buy.quantity) - ? new BigNumber(0) - : sellWithFees.dividedBy(buy.quantity) + const calculatePricesWithFees = (withFrontendFee?: boolean) => { + // add up all that's being sold in sell terms + const sellWithBatcher = new BigNumber(sell.quantity).plus( + feeInSellSideQuantities.batcherFee, + ) + const sellWithFees = withFrontendFee + ? sellWithBatcher.plus(feeInSellSideQuantities.frontendFee) + : sellWithBatcher - const priceWithSlippage = Quantities.isZero(buy.quantity) - ? Quantities.zero - : new BigNumber(sell.quantity) - .dividedBy(buyAmountWithSlippage.quantity) - .toString() + const priceWithFees = Quantities.isZero(buy.quantity) + ? new BigNumber(0) + : sellWithFees.dividedBy(buy.quantity) - const priceWithFeesAndSlippage = Quantities.isZero(buy.quantity) - ? Quantities.zero - : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() + const priceWithFeesAndSlippage = Quantities.isZero( + buyAmountWithSlippage.quantity, + ) + ? Quantities.zero + : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() - // always based, if is limit it can lead to a weird percentage - const priceDifference = priceWithFees - .minus(priceBase) - .dividedBy(priceBase) - .times(100) - .toString() + // always based, if is limit it can lead to a weird percentage + const priceDifference = priceWithFees + .minus(priceBase) + .dividedBy(priceBase) + .times(100) + .toString() - const poolSupply = - buy.tokenId === pool.tokenA.tokenId - ? pool.tokenA.quantity - : pool.tokenB.quantity - const hasSupply = !Quantities.isGreaterThan( - buy.quantity, - poolSupply ?? Quantities.zero, - ) + return { + priceWithFees: asQuantity(priceWithFees), + priceWithFeesAndSlippage: asQuantity(priceWithFeesAndSlippage), + priceDifference: asQuantity(priceDifference), + } + } + const { + priceWithFees: withFees, + priceWithFeesAndSlippage: withFeesAndSlippage, + priceDifference: difference, + } = calculatePricesWithFees(true) + const { + priceWithFees: withFeesNoFEF, + priceWithFeesAndSlippage: withFeesAndSlippageNoFEF, + priceDifference: differenceNoFEF, + } = calculatePricesWithFees(false) return { cost: { batcherFee: pool.batcherFee, @@ -145,10 +170,13 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: asQuantity(priceWithFees), - withSlippage: asQuantity(priceWithSlippage), - withFeesAndSlippage: asQuantity(priceWithFeesAndSlippage), - difference: asQuantity(priceDifference), + withSlippage: priceWithSlippage, + withFees, + withFeesAndSlippage, + difference, + withFeesNoFEF, + withFeesAndSlippageNoFEF, + differenceNoFEF, }, pool, } diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 730b8f7622..6153bdb46b 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -12,10 +12,13 @@ export type SwapOrderCalculation = Readonly<{ prices: { base: Balance.Quantity market: Balance.Quantity - withFees: Balance.Quantity - difference: Balance.Quantity withSlippage: Balance.Quantity + withFees: Balance.Quantity withFeesAndSlippage: Balance.Quantity + difference: Balance.Quantity + withFeesNoFEF: Balance.Quantity + withFeesAndSlippageNoFEF: Balance.Quantity + differenceNoFEF: Balance.Quantity } hasSupply: boolean buyAmountWithSlippage: Balance.Amount From fc7659a62887a23d66cb492847e7b4bc1d429ef6 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Fri, 6 Oct 2023 13:34:12 +0200 Subject: [PATCH 25/67] Show fees --- .../ExpandableInfoCard/ExpandableInfoCard.tsx | 26 +- .../src/features/Swap/common/strings.ts | 10 + .../CreateOrder/EditPool/ShowPoolActions.tsx | 162 ++-- .../wallet-mobile/src/i18n/locales/en-US.json | 4 +- .../src/features/Swap/common/strings.json | 774 +++++++++--------- 5 files changed, 520 insertions(+), 456 deletions(-) diff --git a/apps/wallet-mobile/src/components/ExpandableInfoCard/ExpandableInfoCard.tsx b/apps/wallet-mobile/src/components/ExpandableInfoCard/ExpandableInfoCard.tsx index aa84202c34..1d930466cf 100644 --- a/apps/wallet-mobile/src/components/ExpandableInfoCard/ExpandableInfoCard.tsx +++ b/apps/wallet-mobile/src/components/ExpandableInfoCard/ExpandableInfoCard.tsx @@ -11,7 +11,7 @@ import {Spacer} from '../Spacer' export type ExpandableInfoCardProps = { info: React.ReactNode expanded?: boolean - children: React.ReactNode + children?: React.ReactNode header: React.ReactNode footer?: React.ReactNode withBoxShadow?: boolean @@ -32,17 +32,29 @@ export const ExpandableInfoCard = ({ {header} - + {children !== undefined && ( + <> + - {children} + {children} + + )} - + {expanded && ( + <> + - {expanded && info} + {info} + + )} - {footer != null && footer} + {footer !== undefined && ( + <> + - + {footer} + + )} diff --git a/apps/wallet-mobile/src/features/Swap/common/strings.ts b/apps/wallet-mobile/src/features/Swap/common/strings.ts index be2693384f..f87a21bf21 100644 --- a/apps/wallet-mobile/src/features/Swap/common/strings.ts +++ b/apps/wallet-mobile/src/features/Swap/common/strings.ts @@ -27,11 +27,13 @@ export const useStrings = () => { defaultSlippage: intl.formatMessage(messages.defaultSlippage), slippageInfo: intl.formatMessage(messages.slippageInfo), autoPool: intl.formatMessage(messages.autoPool), + changePool: intl.formatMessage(messages.changePool), swapMinAda: intl.formatMessage(messages.swapMinAda), swapMinAdaTitle: intl.formatMessage(messages.swapMinAdaTitle), swapMinReceived: intl.formatMessage(messages.swapMinReceived), swapMinReceivedTitle: intl.formatMessage(messages.swapMinReceivedTitle), swapFeesTitle: intl.formatMessage(messages.swapFeesTitle), + swapLiquidityFee: (fee: string) => intl.formatMessage(messages.swapLiquidityFee, {fee}), swapFees: intl.formatMessage(messages.swapFees), poolVerification: (pool: string) => intl.formatMessage(messages.poolVerification, {pool}), poolVerificationInfo: (pool: string) => intl.formatMessage(messages.poolVerificationInfo, {pool}), @@ -198,6 +200,10 @@ export const messages = defineMessages({ id: 'swap.swapScreen.autoPool', defaultMessage: '!!!(auto)', }, + changePool: { + id: 'swap.swapScreen.changePool', + defaultMessage: '!!!change pool', + }, swapMinAda: { id: 'swap.swapScreen.swapMinAda', defaultMessage: @@ -215,6 +221,10 @@ export const messages = defineMessages({ id: 'swap.swapScreen.swapFeesTitle', defaultMessage: `!!!Fees`, }, + swapLiquidityFee: { + id: 'swap.swapScreen.swapLiquidityFee', + defaultMessage: `!!!Liquidity provider fee ({fee}%)`, + }, swapMinReceived: { id: 'swap.swapScreen.swapMinReceived', defaultMessage: '!!!Minimum amount of tokens you can get because of the slippage tolerance.', diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx index 3ca04eac03..aa72996390 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx @@ -8,11 +8,11 @@ import { ExpandableInfoCard, HeaderWrapper, HiddenInfoWrapper, - MainInfoWrapper, Spacer, } from '../../../../../../components' import {useLanguage} from '../../../../../../i18n' import {useSelectedWallet} from '../../../../../../SelectedWallet' +import {COLORS} from '../../../../../../theme' import {useTokenInfo} from '../../../../../../yoroi-wallets/hooks' import {Quantities} from '../../../../../../yoroi-wallets/utils' import {useNavigateTo} from '../../../../common/navigation' @@ -29,14 +29,19 @@ export const ShowPoolActions = () => { const {calculatedPool, amounts} = orderData const wallet = useSelectedWallet() const buyTokenInfo = useTokenInfo({wallet, tokenId: amounts.buy.tokenId}) - const tokenName = buyTokenInfo.ticker ?? buyTokenInfo.name + const sellTokenInfo = useTokenInfo({wallet, tokenId: amounts.sell.tokenId}) + const buyTokenName = buyTokenInfo.ticker ?? buyTokenInfo.name + const sellTokenName = sellTokenInfo.ticker ?? sellTokenInfo.name const [hiddenInfoOpenId, setHiddenInfoOpenId] = React.useState(null) if (!isBuyTouched || !isSellTouched || calculatedPool === undefined) { return <> } - const totalAmount = Quantities.format(amounts.buy.quantity, buyTokenInfo.decimals ?? 0) + const totalFees = Quantities.format( + Quantities.sum([calculatedPool.cost.batcherFee.quantity, calculatedPool.cost.frontendFeeInfo.fee.quantity]), + Number(wallet.primaryTokenInfo.decimals), + ) const id = calculatedPool.pool.poolId const expanded = id === hiddenInfoOpenId @@ -44,68 +49,63 @@ export const ShowPoolActions = () => { const poolStatus = orderData.type === 'limit' && isPoolTouched ? '' : ` ${strings.autoPool}` const poolTitle = `${poolProviderFormatted}${poolStatus}` + const handlePress = () => setHiddenInfoOpenId(hiddenInfoOpenId !== id ? id : null) + return ( - setHiddenInfoOpenId(hiddenInfoOpenId !== id ? id : null)} - onPressLabel={() => { - if (orderData.type === 'limit') { - navigateTo.selectPool() - } else { - setHiddenInfoOpenId(hiddenInfoOpenId !== id ? id : null) - } - }} - expanded={expanded} - > - - + + + + - + - {poolTitle} - -
- } - info={ - - } - expanded={expanded} - > - - - ) -} + {poolTitle} + -const Header = ({ - children, - expanded, - onPressExpand, - onPressLabel, -}: { - children: React.ReactNode - expanded?: boolean - onPressExpand: () => void - onPressLabel: () => void -}) => { - return ( - - {children} - + {orderData.type === 'limit' && ( + navigateTo.selectPool()}> + {strings.changePool} + + )} + + + + + {`${strings.total}: ${Quantities.format( + amounts.sell.quantity, + sellTokenInfo.decimals ?? 0, + )} ${sellTokenName} + ${totalFees} ${wallet.primaryTokenInfo.ticker}`} + + + } + info={ + + } + expanded={expanded} + /> + ) } @@ -114,11 +114,17 @@ const HiddenInfo = ({ minAda, minReceived, buyTokenName, + sellTokenName, + liquidityFee, + liquidityFeeValue, }: { totalFees: string minAda: string minReceived: string buyTokenName: string + sellTokenName: string + liquidityFee: string + liquidityFeeValue: string }) => { const [bottomSheetState, setBottomSheetSate] = React.useState<{isOpen: boolean; title: string; content?: string}>({ isOpen: false, @@ -136,15 +142,19 @@ const HiddenInfo = ({ value: `${minAda} ${wallet.primaryTokenInfo.ticker}`, info: strings.swapMinAda, }, + { + label: strings.swapFeesTitle, + value: `${totalFees} ${wallet.primaryTokenInfo.ticker}`, + info: strings.swapFees, + }, { label: strings.swapMinReceivedTitle, value: `${minReceived} ${buyTokenName}`, info: strings.swapMinReceived, }, { - label: strings.swapFeesTitle, - value: `${totalFees} ${wallet.primaryTokenInfo.ticker}`, - info: strings.swapFees, + label: strings.swapLiquidityFee(liquidityFee), + value: `${liquidityFeeValue} ${sellTokenName}`, }, ].map((item) => ( { - const strings = useStrings() - - return ( - - {[{label: `${strings.total} ${totalAmount} ${tokenName} `}].map((item, index) => ( - - ))} - - ) -} - const styles = StyleSheet.create({ flex: {flexDirection: 'row', alignItems: 'center'}, + between: {justifyContent: 'space-between'}, text: { textAlign: 'left', fontSize: 16, @@ -196,4 +195,15 @@ const styles = StyleSheet.create({ fontWeight: '400', color: '#242838', }, + change: {color: COLORS.SHELLEY_BLUE, fontWeight: '600', textTransform: 'uppercase'}, + bold: { + color: COLORS.BLACK, + fontWeight: '400', + fontFamily: 'Rubik-Regular', + }, + bolder: { + color: COLORS.BLACK, + fontWeight: '500', + fontFamily: 'Rubik-Medium', + }, }) diff --git a/apps/wallet-mobile/src/i18n/locales/en-US.json b/apps/wallet-mobile/src/i18n/locales/en-US.json index 6fc1bd0229..74fa00e732 100644 --- a/apps/wallet-mobile/src/i18n/locales/en-US.json +++ b/apps/wallet-mobile/src/i18n/locales/en-US.json @@ -157,10 +157,12 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/strings.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/strings.json index 01348d4d1c..ea9019b10e 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/strings.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/strings.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Incorrect password.", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 117, + "line": 119, "column": 24, - "index": 7321 + "index": 7471 }, "end": { - "line": 120, + "line": 122, "column": 3, - "index": 7430 + "index": 7580 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!Swap", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 121, + "line": 123, "column": 13, - "index": 7445 + "index": 7595 }, "end": { - "line": 124, + "line": 126, "column": 3, - "index": 7518 + "index": 7668 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!Token swap", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 125, + "line": 127, "column": 13, - "index": 7533 + "index": 7683 }, "end": { - "line": 128, + "line": 130, "column": 3, - "index": 7615 + "index": 7765 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Orders", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 129, + "line": 131, "column": 13, - "index": 7630 + "index": 7780 }, "end": { - "line": 132, + "line": 134, "column": 3, - "index": 7709 + "index": 7859 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!!Market Button", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 133, + "line": 135, "column": 16, - "index": 7727 + "index": 7877 }, "end": { - "line": 136, + "line": 138, "column": 3, - "index": 7812 + "index": 7962 } }, { @@ -79,14 +79,14 @@ "defaultMessage": "!!!Limit", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 137, + "line": 139, "column": 15, - "index": 7829 + "index": 7979 }, "end": { - "line": 140, + "line": 142, "column": 3, - "index": 7905 + "index": 8055 } }, { @@ -94,14 +94,14 @@ "defaultMessage": "!!!Swap from", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 141, + "line": 143, "column": 12, - "index": 7919 + "index": 8069 }, "end": { - "line": 144, + "line": 146, "column": 3, - "index": 7996 + "index": 8146 } }, { @@ -109,14 +109,14 @@ "defaultMessage": "!!!Swap to", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 145, + "line": 147, "column": 10, - "index": 8008 + "index": 8158 }, "end": { - "line": 148, + "line": 150, "column": 3, - "index": 8081 + "index": 8231 } }, { @@ -124,14 +124,14 @@ "defaultMessage": "!!!Current Balance", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 149, + "line": 151, "column": 18, - "index": 8101 + "index": 8251 }, "end": { - "line": 152, + "line": 154, "column": 3, - "index": 8190 + "index": 8340 } }, { @@ -139,14 +139,14 @@ "defaultMessage": "!!!Balance", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 153, + "line": 155, "column": 11, - "index": 8203 + "index": 8353 }, "end": { - "line": 156, + "line": 158, "column": 3, - "index": 8277 + "index": 8427 } }, { @@ -154,14 +154,14 @@ "defaultMessage": "!!!Select Token", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 157, + "line": 159, "column": 15, - "index": 8294 + "index": 8444 }, "end": { - "line": 160, + "line": 162, "column": 3, - "index": 8377 + "index": 8527 } }, { @@ -169,14 +169,14 @@ "defaultMessage": "!!!Market Price", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 161, + "line": 163, "column": 15, - "index": 8394 + "index": 8544 }, "end": { - "line": 164, + "line": 166, "column": 3, - "index": 8477 + "index": 8627 } }, { @@ -184,14 +184,14 @@ "defaultMessage": "!!!Limit Price", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 165, + "line": 167, "column": 14, - "index": 8493 + "index": 8643 }, "end": { - "line": 168, + "line": 170, "column": 3, - "index": 8574 + "index": 8724 } }, { @@ -199,14 +199,14 @@ "defaultMessage": "!!!Slippage Tolerance", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 169, + "line": 171, "column": 21, - "index": 8597 + "index": 8747 }, "end": { - "line": 172, + "line": 174, "column": 3, - "index": 8692 + "index": 8842 } }, { @@ -214,14 +214,14 @@ "defaultMessage": "!!!Slippage must be a number between 0 and 100 and have up to 1 decimal", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 173, + "line": 175, "column": 26, - "index": 8720 + "index": 8870 }, "end": { - "line": 176, + "line": 178, "column": 3, - "index": 8870 + "index": 9020 } }, { @@ -229,14 +229,14 @@ "defaultMessage": "!!!Slippage Tolerance Info", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 177, + "line": 179, "column": 25, - "index": 8897 + "index": 9047 }, "end": { - "line": 180, + "line": 182, "column": 3, - "index": 9001 + "index": 9151 } }, { @@ -244,14 +244,14 @@ "defaultMessage": "!!!Verified by {pool}", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 181, + "line": 183, "column": 14, - "index": 9017 + "index": 9167 }, "end": { - "line": 184, + "line": 186, "column": 3, - "index": 9105 + "index": 9255 } }, { @@ -259,14 +259,14 @@ "defaultMessage": "!!!This asset is in my portfolio", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 185, + "line": 187, "column": 12, - "index": 9119 + "index": 9269 }, "end": { - "line": 188, + "line": 190, "column": 3, - "index": 9216 + "index": 9366 } }, { @@ -274,14 +274,14 @@ "defaultMessage": "!!!Default Slippage Tolerance", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 189, + "line": 191, "column": 19, - "index": 9237 + "index": 9387 }, "end": { - "line": 192, + "line": 194, "column": 3, - "index": 9338 + "index": 9488 } }, { @@ -289,14 +289,14 @@ "defaultMessage": "!!!Slippage tolerance is set as a percentage of the total swap value.", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 193, + "line": 195, "column": 16, - "index": 9356 + "index": 9506 }, "end": { - "line": 196, + "line": 198, "column": 3, - "index": 9494 + "index": 9644 } }, { @@ -304,14 +304,29 @@ "defaultMessage": "!!!(auto)", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 197, + "line": 199, "column": 12, - "index": 9508 + "index": 9658 }, "end": { - "line": 200, + "line": 202, "column": 3, - "index": 9582 + "index": 9732 + } + }, + { + "id": "swap.swapScreen.changePool", + "defaultMessage": "!!!change pool", + "file": "src/features/Swap/common/strings.ts", + "start": { + "line": 203, + "column": 14, + "index": 9748 + }, + "end": { + "line": 206, + "column": 3, + "index": 9829 } }, { @@ -319,14 +334,14 @@ "defaultMessage": "!!!Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 201, + "line": 207, "column": 14, - "index": 9598 + "index": 9845 }, "end": { - "line": 205, + "line": 211, "column": 3, - "index": 9779 + "index": 10026 } }, { @@ -334,14 +349,14 @@ "defaultMessage": "!!!Min ADA", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 206, + "line": 212, "column": 19, - "index": 9800 + "index": 10047 }, "end": { - "line": 209, + "line": 215, "column": 3, - "index": 9882 + "index": 10129 } }, { @@ -349,14 +364,14 @@ "defaultMessage": "!!!Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 210, + "line": 216, "column": 12, - "index": 9896 + "index": 10143 }, "end": { - "line": 213, + "line": 219, "column": 3, - "index": 10059 + "index": 10306 } }, { @@ -364,14 +379,29 @@ "defaultMessage": "!!!Fees", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 214, + "line": 220, "column": 17, - "index": 10078 + "index": 10325 }, "end": { - "line": 217, + "line": 223, "column": 3, - "index": 10155 + "index": 10402 + } + }, + { + "id": "swap.swapScreen.swapLiquidityFee", + "defaultMessage": "!!!Liquidity provider fee ({fee}%)", + "file": "src/features/Swap/common/strings.ts", + "start": { + "line": 224, + "column": 20, + "index": 10424 + }, + "end": { + "line": 227, + "column": 3, + "index": 10531 } }, { @@ -379,14 +409,14 @@ "defaultMessage": "!!!Minimum amount of tokens you can get because of the slippage tolerance.", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 218, + "line": 228, "column": 19, - "index": 10176 + "index": 10552 }, "end": { - "line": 221, + "line": 231, "column": 3, - "index": 10322 + "index": 10698 } }, { @@ -394,14 +424,14 @@ "defaultMessage": "!!!Min Received", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 222, + "line": 232, "column": 24, - "index": 10348 + "index": 10724 }, "end": { - "line": 225, + "line": 235, "column": 3, - "index": 10440 + "index": 10816 } }, { @@ -409,14 +439,14 @@ "defaultMessage": "!!!Enter a value from 0% to 100%. You can also enter up to 1 decimal", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 226, + "line": 236, "column": 17, - "index": 10459 + "index": 10835 }, "end": { - "line": 229, + "line": 239, "column": 3, - "index": 10597 + "index": 10973 } }, { @@ -424,14 +454,14 @@ "defaultMessage": "!!!{pool} verification", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 230, + "line": 240, "column": 20, - "index": 10619 + "index": 10995 }, "end": { - "line": 233, + "line": 243, "column": 3, - "index": 10714 + "index": 11090 } }, { @@ -439,14 +469,14 @@ "defaultMessage": "!!!Volume, 24h", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 234, + "line": 244, "column": 10, - "index": 10726 + "index": 11102 }, "end": { - "line": 237, + "line": 247, "column": 3, - "index": 10803 + "index": 11179 } }, { @@ -454,14 +484,14 @@ "defaultMessage": "!!!Cardano projects that list their own tokens can apply for an additional {pool} verification. This verification is a manual validation that {pool} team performs with the help of Cardano Foundation.", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 238, + "line": 248, "column": 24, - "index": 10829 + "index": 11205 }, "end": { - "line": 242, + "line": 252, "column": 3, - "index": 11111 + "index": 11487 } }, { @@ -469,14 +499,14 @@ "defaultMessage": "!!! Price", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 243, + "line": 253, "column": 9, - "index": 11122 + "index": 11498 }, "end": { - "line": 246, + "line": 256, "column": 3, - "index": 11184 + "index": 11560 } }, { @@ -484,14 +514,14 @@ "defaultMessage": "!!!No assets found for this pair", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 247, + "line": 257, "column": 17, - "index": 11203 + "index": 11579 }, "end": { - "line": 250, + "line": 260, "column": 3, - "index": 11305 + "index": 11681 } }, { @@ -499,14 +529,14 @@ "defaultMessage": "!!!No assets found for \"{search}\"", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 251, + "line": 261, "column": 20, - "index": 11327 + "index": 11703 }, "end": { - "line": 254, + "line": 264, "column": 3, - "index": 11433 + "index": 11809 } }, { @@ -514,14 +544,14 @@ "defaultMessage": "!!!Each verified tokens gets", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 255, + "line": 265, "column": 21, - "index": 11456 + "index": 11832 }, "end": { - "line": 258, + "line": 268, "column": 3, - "index": 11558 + "index": 11934 } }, { @@ -529,14 +559,14 @@ "defaultMessage": "!!!verified badge", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 259, + "line": 269, "column": 17, - "index": 11577 + "index": 11953 }, "end": { - "line": 262, + "line": 272, "column": 3, - "index": 11664 + "index": 12040 } }, { @@ -544,14 +574,14 @@ "defaultMessage": "!!!Open orders", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 263, + "line": 273, "column": 14, - "index": 11680 + "index": 12056 }, "end": { - "line": 266, + "line": 276, "column": 3, - "index": 11761 + "index": 12137 } }, { @@ -559,14 +589,14 @@ "defaultMessage": "!!!Completed orders", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 267, + "line": 277, "column": 19, - "index": 11782 + "index": 12158 }, "end": { - "line": 270, + "line": 280, "column": 3, - "index": 11873 + "index": 12249 } }, { @@ -574,14 +604,14 @@ "defaultMessage": "!!!TVL", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 271, + "line": 281, "column": 7, - "index": 11882 + "index": 12258 }, "end": { - "line": 274, + "line": 284, "column": 3, - "index": 11948 + "index": 12324 } }, { @@ -589,14 +619,14 @@ "defaultMessage": "!!! Pool Fee", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 275, + "line": 285, "column": 11, - "index": 11961 + "index": 12337 }, "end": { - "line": 278, + "line": 288, "column": 3, - "index": 12037 + "index": 12413 } }, { @@ -604,14 +634,14 @@ "defaultMessage": "!!! Batcher Fee", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 279, + "line": 289, "column": 14, - "index": 12053 + "index": 12429 }, "end": { - "line": 282, + "line": 292, "column": 3, - "index": 12135 + "index": 12511 } }, { @@ -619,14 +649,14 @@ "defaultMessage": "!!!Limit price", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 283, + "line": 293, "column": 26, - "index": 12163 + "index": 12539 }, "end": { - "line": 286, + "line": 296, "column": 3, - "index": 12256 + "index": 12632 } }, { @@ -634,14 +664,14 @@ "defaultMessage": "!!!Are you sure you want to proceed this order with the limit price that is 10% or more higher than the\nmarket price?", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 287, + "line": 297, "column": 32, - "index": 12290 + "index": 12666 }, "end": { - "line": 292, + "line": 302, "column": 3, - "index": 12510 + "index": 12886 } }, { @@ -649,14 +679,14 @@ "defaultMessage": "!!!Your limit price", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 293, + "line": 303, "column": 30, - "index": 12542 + "index": 12918 }, "end": { - "line": 296, + "line": 306, "column": 3, - "index": 12644 + "index": 13020 } }, { @@ -664,14 +694,14 @@ "defaultMessage": "!!!Market price", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 297, + "line": 307, "column": 32, - "index": 12678 + "index": 13054 }, "end": { - "line": 300, + "line": 310, "column": 3, - "index": 12778 + "index": 13154 } }, { @@ -679,14 +709,14 @@ "defaultMessage": "!!!Back", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 301, + "line": 311, "column": 25, - "index": 12805 + "index": 13181 }, "end": { - "line": 304, + "line": 314, "column": 3, - "index": 12890 + "index": 13266 } }, { @@ -694,14 +724,14 @@ "defaultMessage": "!!!Swap", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 305, + "line": 315, "column": 28, - "index": 12920 + "index": 13296 }, "end": { - "line": 308, + "line": 318, "column": 3, - "index": 13008 + "index": 13384 } }, { @@ -709,14 +739,14 @@ "defaultMessage": "!!!Transaction signed", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 309, + "line": 319, "column": 21, - "index": 13031 + "index": 13407 }, "end": { - "line": 312, + "line": 322, "column": 3, - "index": 13126 + "index": 13502 } }, { @@ -724,14 +754,14 @@ "defaultMessage": "!!!Your transactions will be displayed both in the list of transaction and Open swap orders", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 313, + "line": 323, "column": 22, - "index": 13150 + "index": 13526 }, "end": { - "line": 316, + "line": 326, "column": 3, - "index": 13316 + "index": 13692 } }, { @@ -739,14 +769,14 @@ "defaultMessage": "!!!see on explorer", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 317, + "line": 327, "column": 17, - "index": 13335 + "index": 13711 }, "end": { - "line": 320, + "line": 330, "column": 3, - "index": 13423 + "index": 13799 } }, { @@ -754,14 +784,14 @@ "defaultMessage": "!!!GO to Orders", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 321, + "line": 331, "column": 14, - "index": 13439 + "index": 13815 }, "end": { - "line": 324, + "line": 334, "column": 3, - "index": 13521 + "index": 13897 } }, { @@ -769,14 +799,14 @@ "defaultMessage": "!!!Asset", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 325, + "line": 335, "column": 9, - "index": 13532 + "index": 13908 }, "end": { - "line": 328, + "line": 338, "column": 3, - "index": 13605 + "index": 13981 } }, { @@ -784,14 +814,14 @@ "defaultMessage": "!!!Clear", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 329, + "line": 339, "column": 9, - "index": 13616 + "index": 13992 }, "end": { - "line": 332, + "line": 342, "column": 3, - "index": 13677 + "index": 14053 } }, { @@ -799,14 +829,14 @@ "defaultMessage": "!!!Sign transaction", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 333, + "line": 343, "column": 19, - "index": 13698 + "index": 14074 }, "end": { - "line": 336, + "line": 346, "column": 3, - "index": 13780 + "index": 14156 } }, { @@ -814,14 +844,14 @@ "defaultMessage": "!!!Spending Password", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 337, + "line": 347, "column": 20, - "index": 13802 + "index": 14178 }, "end": { - "line": 340, + "line": 350, "column": 3, - "index": 13886 + "index": 14262 } }, { @@ -829,14 +859,14 @@ "defaultMessage": "!!!Enter spending password to sign this transaction", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 341, + "line": 351, "column": 25, - "index": 13913 + "index": 14289 }, "end": { - "line": 344, + "line": 354, "column": 3, - "index": 14033 + "index": 14409 } }, { @@ -844,14 +874,14 @@ "defaultMessage": "!!!Sign", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 345, + "line": 355, "column": 8, - "index": 14043 + "index": 14419 }, "end": { - "line": 348, + "line": 358, "column": 3, - "index": 14102 + "index": 14478 } }, { @@ -859,14 +889,14 @@ "defaultMessage": "!!!Swap", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 349, + "line": 359, "column": 14, - "index": 14118 + "index": 14494 }, "end": { - "line": 352, + "line": 362, "column": 3, - "index": 14177 + "index": 14553 } }, { @@ -874,14 +904,14 @@ "defaultMessage": "!!!completed orders", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 353, + "line": 363, "column": 23, - "index": 14202 + "index": 14578 }, "end": { - "line": 356, + "line": 366, "column": 3, - "index": 14287 + "index": 14663 } }, { @@ -889,14 +919,14 @@ "defaultMessage": "!!!open orders", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 357, + "line": 367, "column": 18, - "index": 14307 + "index": 14683 }, "end": { - "line": 360, + "line": 370, "column": 3, - "index": 14382 + "index": 14758 } }, { @@ -904,14 +934,14 @@ "defaultMessage": "!!!Confirm order cancelation", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 361, + "line": 371, "column": 24, - "index": 14408 + "index": 14784 }, "end": { - "line": 364, + "line": 374, "column": 3, - "index": 14504 + "index": 14880 } }, { @@ -919,14 +949,14 @@ "defaultMessage": "!!!Cancel order", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 365, + "line": 375, "column": 29, - "index": 14535 + "index": 14911 }, "end": { - "line": 368, + "line": 378, "column": 3, - "index": 14622 + "index": 14998 } }, { @@ -934,14 +964,14 @@ "defaultMessage": "!!!Are you sure you want to cancel this order?", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 369, + "line": 379, "column": 31, - "index": 14655 + "index": 15031 }, "end": { - "line": 372, + "line": 382, "column": 3, - "index": 14776 + "index": 15152 } }, { @@ -949,14 +979,14 @@ "defaultMessage": "!!!Learn more about swap orders in Yoroi", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 373, + "line": 383, "column": 23, - "index": 14801 + "index": 15177 }, "end": { - "line": 376, + "line": 386, "column": 3, - "index": 14908 + "index": 15284 } }, { @@ -964,14 +994,14 @@ "defaultMessage": "!!!Asset price", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 377, + "line": 387, "column": 29, - "index": 14939 + "index": 15315 }, "end": { - "line": 380, + "line": 390, "column": 3, - "index": 15026 + "index": 15402 } }, { @@ -979,14 +1009,14 @@ "defaultMessage": "!!!Asset amount", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 381, + "line": 391, "column": 30, - "index": 15058 + "index": 15434 }, "end": { - "line": 384, + "line": 394, "column": 3, - "index": 15147 + "index": 15523 } }, { @@ -994,14 +1024,14 @@ "defaultMessage": "!!!Total returned", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 385, + "line": 395, "column": 32, - "index": 15181 + "index": 15557 }, "end": { - "line": 388, + "line": 398, "column": 3, - "index": 15274 + "index": 15650 } }, { @@ -1009,14 +1039,14 @@ "defaultMessage": "!!!Cancellation Fee", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 389, + "line": 399, "column": 34, - "index": 15310 + "index": 15686 }, "end": { - "line": 392, + "line": 402, "column": 3, - "index": 15407 + "index": 15783 } }, { @@ -1024,14 +1054,14 @@ "defaultMessage": "!!!Confirm", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 393, + "line": 403, "column": 26, - "index": 15435 + "index": 15811 }, "end": { - "line": 396, + "line": 406, "column": 3, - "index": 15515 + "index": 15891 } }, { @@ -1039,14 +1069,14 @@ "defaultMessage": "!!!Back", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 397, + "line": 407, "column": 23, - "index": 15540 + "index": 15916 }, "end": { - "line": 400, + "line": 410, "column": 3, - "index": 15614 + "index": 15990 } }, { @@ -1054,14 +1084,14 @@ "defaultMessage": "!!!Total", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 401, + "line": 411, "column": 19, - "index": 15635 + "index": 16011 }, "end": { - "line": 404, + "line": 414, "column": 3, - "index": 15705 + "index": 16081 } }, { @@ -1069,14 +1099,14 @@ "defaultMessage": "!!!Liquidity Pool", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 405, + "line": 415, "column": 27, - "index": 15734 + "index": 16110 }, "end": { - "line": 408, + "line": 418, "column": 3, - "index": 15821 + "index": 16197 } }, { @@ -1084,14 +1114,14 @@ "defaultMessage": "!!!Time Created", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 409, + "line": 419, "column": 25, - "index": 15848 + "index": 16224 }, "end": { - "line": 412, + "line": 422, "column": 3, - "index": 15931 + "index": 16307 } }, { @@ -1099,14 +1129,14 @@ "defaultMessage": "!!!Transaction ID", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 413, + "line": 423, "column": 18, - "index": 15951 + "index": 16327 }, "end": { - "line": 416, + "line": 426, "column": 3, - "index": 16029 + "index": 16405 } }, { @@ -1114,14 +1144,14 @@ "defaultMessage": "!!!Choose Connection Method", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 417, + "line": 427, "column": 26, - "index": 16057 + "index": 16433 }, "end": { - "line": 420, + "line": 430, "column": 3, - "index": 16175 + "index": 16551 } }, { @@ -1129,14 +1159,14 @@ "defaultMessage": "!!!Choose this option if you want to connect to a Ledger Nano model X or S using an on-the-go USB cable adaptor:", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 421, + "line": 431, "column": 18, - "index": 16195 + "index": 16571 }, "end": { - "line": 426, + "line": 436, "column": 3, - "index": 16424 + "index": 16800 } }, { @@ -1144,14 +1174,14 @@ "defaultMessage": "!!!Connect with USB", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 427, + "line": 437, "column": 13, - "index": 16439 + "index": 16815 }, "end": { - "line": 430, + "line": 440, "column": 3, - "index": 16553 + "index": 16929 } }, { @@ -1159,14 +1189,14 @@ "defaultMessage": "!!! USB connection is blocked by iOS devices", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 431, + "line": 441, "column": 26, - "index": 16581 + "index": 16957 }, "end": { - "line": 434, + "line": 444, "column": 3, - "index": 16733 + "index": 17109 } }, { @@ -1174,14 +1204,14 @@ "defaultMessage": "!!!Choose this option if you want to connect to a Ledger Nano model X through Bluetooth:", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 435, + "line": 445, "column": 24, - "index": 16759 + "index": 17135 }, "end": { - "line": 438, + "line": 448, "column": 3, - "index": 16953 + "index": 17329 } }, { @@ -1189,14 +1219,14 @@ "defaultMessage": "!!!Connect with Bluetooth", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 439, + "line": 449, "column": 19, - "index": 16974 + "index": 17350 }, "end": { - "line": 442, + "line": 452, "column": 3, - "index": 17100 + "index": 17476 } }, { @@ -1204,14 +1234,14 @@ "defaultMessage": "!!!Connect with Bluetooth", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 443, + "line": 453, "column": 18, - "index": 17120 + "index": 17496 }, "end": { - "line": 446, + "line": 456, "column": 3, - "index": 17230 + "index": 17606 } }, { @@ -1219,14 +1249,14 @@ "defaultMessage": "!!!You have", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 449, + "line": 459, "column": 11, - "index": 17289 + "index": 17665 }, "end": { - "line": 452, + "line": 462, "column": 3, - "index": 17384 + "index": 17760 } }, { @@ -1234,14 +1264,14 @@ "defaultMessage": "!!!No assets found", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 453, + "line": 463, "column": 12, - "index": 17398 + "index": 17774 }, "end": { - "line": 456, + "line": 466, "column": 3, - "index": 17501 + "index": 17877 } }, { @@ -1249,14 +1279,14 @@ "defaultMessage": "!!!found", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 457, + "line": 467, "column": 9, - "index": 17512 + "index": 17888 }, "end": { - "line": 460, + "line": 470, "column": 3, - "index": 17602 + "index": 17978 } }, { @@ -1264,14 +1294,14 @@ "defaultMessage": "!!!Search tokens", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 461, + "line": 471, "column": 16, - "index": 17620 + "index": 17996 }, "end": { - "line": 464, + "line": 474, "column": 3, - "index": 17716 + "index": 18092 } }, { @@ -1279,14 +1309,14 @@ "defaultMessage": "!!!Select asset", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 465, + "line": 475, "column": 20, - "index": 17738 + "index": 18114 }, "end": { - "line": 468, + "line": 478, "column": 3, - "index": 17827 + "index": 18203 } }, { @@ -1294,14 +1324,14 @@ "defaultMessage": "!!!Confirm", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 469, + "line": 479, "column": 11, - "index": 17840 + "index": 18216 }, "end": { - "line": 472, + "line": 482, "column": 3, - "index": 17934 + "index": 18310 } }, { @@ -1309,14 +1339,14 @@ "defaultMessage": "!!!Assign collateral", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 473, + "line": 483, "column": 20, - "index": 17956 + "index": 18332 }, "end": { - "line": 476, + "line": 486, "column": 3, - "index": 18063 + "index": 18439 } }, { @@ -1324,14 +1354,14 @@ "defaultMessage": "!!!Collateral not found", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 477, + "line": 487, "column": 22, - "index": 18087 + "index": 18463 }, "end": { - "line": 480, + "line": 490, "column": 3, - "index": 18199 + "index": 18575 } }, { @@ -1339,14 +1369,14 @@ "defaultMessage": "!!!You don't have an active collateral utxo", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 481, + "line": 491, "column": 22, - "index": 18223 + "index": 18599 }, "end": { - "line": 484, + "line": 494, "column": 3, - "index": 18355 + "index": 18731 } }, { @@ -1354,14 +1384,14 @@ "defaultMessage": "!!!Transaction failed", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 485, + "line": 495, "column": 17, - "index": 18374 + "index": 18750 }, "end": { - "line": 488, + "line": 498, "column": 3, - "index": 18476 + "index": 18852 } }, { @@ -1369,14 +1399,14 @@ "defaultMessage": "!!!Your transaction has not been processed properly due to technical issues", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 489, + "line": 499, "column": 16, - "index": 18494 + "index": 18870 }, "end": { - "line": 492, + "line": 502, "column": 3, - "index": 18649 + "index": 19025 } }, { @@ -1384,14 +1414,14 @@ "defaultMessage": "!!!Try again", "file": "src/features/Swap/common/strings.ts", "start": { - "line": 493, + "line": 503, "column": 18, - "index": 18669 + "index": 19045 }, "end": { - "line": 496, + "line": 506, "column": 3, - "index": 18763 + "index": 19139 } } ] \ No newline at end of file From 379c1a90d4763927fade1c675b1547b96231bef2 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Fri, 6 Oct 2023 18:36:05 +0200 Subject: [PATCH 26/67] Address comments --- apps/wallet-mobile/src/features/Swap/common/mocks.ts | 4 ++-- .../CreateOrder/EditPool/ShowPoolActions.tsx | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/common/mocks.ts b/apps/wallet-mobile/src/features/Swap/common/mocks.ts index f803a6c48c..d540072750 100644 --- a/apps/wallet-mobile/src/features/Swap/common/mocks.ts +++ b/apps/wallet-mobile/src/features/Swap/common/mocks.ts @@ -11,12 +11,12 @@ export const mocks = { ...mockSwapStateDefault.orderData, amounts: { buy: { - quantity: asQuantity(20467572) as `${number}`, + quantity: asQuantity(20467572), tokenId: '208a2ca888886921513cb777bb832a8dc685c04de990480151f12150.53484942414441', }, sell: {quantity: asQuantity(2000000), tokenId: ''}, }, - limitPrice: '0.089' as `${number}`, + limitPrice: '0.089', selectedPool: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.702083', pools: [ { diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx index aa72996390..cbe82ee3da 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx @@ -42,6 +42,10 @@ export const ShowPoolActions = () => { Quantities.sum([calculatedPool.cost.batcherFee.quantity, calculatedPool.cost.frontendFeeInfo.fee.quantity]), Number(wallet.primaryTokenInfo.decimals), ) + const header = `${strings.total}: ${Quantities.format( + amounts.sell.quantity, + sellTokenInfo.decimals ?? 0, + )} ${sellTokenName} + ${totalFees} ${wallet.primaryTokenInfo.ticker}` const id = calculatedPool.pool.poolId const expanded = id === hiddenInfoOpenId @@ -74,10 +78,7 @@ export const ShowPoolActions = () => { header={ - {`${strings.total}: ${Quantities.format( - amounts.sell.quantity, - sellTokenInfo.decimals ?? 0, - )} ${sellTokenName} + ${totalFees} ${wallet.primaryTokenInfo.ticker}`} + {header} } From 931714fcc654776574a0dd71b766d0b641773b76 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Sat, 7 Oct 2023 11:46:58 +0100 Subject: [PATCH 27/67] chore: dropped state pt prices in favor of pool pt price --- .../helpers/orders/makeOrderCalculations.ts | 24 +++++++++---------- .../translators/reactjs/state/state.mocks.ts | 4 ---- .../src/translators/reactjs/state/state.ts | 20 ---------------- 3 files changed, 11 insertions(+), 37 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 417fc5022e..4a92014d28 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -15,7 +15,6 @@ export const makeOrderCalculations = ({ amounts, limitPrice, slippage, - ptPrices, pools, primaryTokenId, lpTokenHeld, @@ -27,10 +26,6 @@ export const makeOrderCalculations = ({ buy: Balance.Amount } limitPrice?: Balance.Quantity - ptPrices: { - buy?: Balance.Quantity - sell?: Balance.Quantity - } pools: ReadonlyArray lpTokenHeld?: Balance.Amount slippage: number @@ -60,10 +55,9 @@ export const makeOrderCalculations = ({ tokenId: buy.tokenId, } - const poolSupply = - buy.tokenId === pool.tokenA.tokenId - ? pool.tokenA.quantity - : pool.tokenB.quantity + // pools that with not enough supply will be filtered out + const isBuyTokenA = buy.tokenId === pool.tokenA.tokenId + const poolSupply = isBuyTokenA ? pool.tokenA.quantity : pool.tokenB.quantity const hasSupply = !Quantities.isGreaterThan( buy.quantity, poolSupply ?? Quantities.zero, @@ -72,6 +66,10 @@ export const makeOrderCalculations = ({ // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) + const [ptPriceBuy, ptPriceSell] = isBuyTokenA + ? [pool.ptPriceTokenA, pool.ptPriceTokenB] + : [pool.ptPriceTokenB, pool.ptPriceTokenA] + // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ sell, @@ -82,7 +80,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.sell.quantity) - .times(ptPrices.sell ?? 0) + .times(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -90,7 +88,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.buy.quantity) - .times(ptPrices.buy ?? 0) + .times(ptPriceBuy) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -100,10 +98,10 @@ export const makeOrderCalculations = ({ // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) - .times(ptPrices.sell ?? 0) + .times(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .times(ptPrices.sell ?? 0) + .times(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), } diff --git a/packages/swap/src/translators/reactjs/state/state.mocks.ts b/packages/swap/src/translators/reactjs/state/state.mocks.ts index f731377882..66018619be 100644 --- a/packages/swap/src/translators/reactjs/state/state.mocks.ts +++ b/packages/swap/src/translators/reactjs/state/state.mocks.ts @@ -20,10 +20,6 @@ export const mockSwapStateDefault: SwapState = { calculations: [], lpTokenHeld: undefined, pools: [], - ptPrices: { - sell: '0', - buy: '0', - }, }, unsignedTx: undefined, } as const diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 6153bdb46b..2cce12e3db 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -65,11 +65,6 @@ export type SwapState = Readonly<{ pools: ReadonlyArray calculations: ReadonlyArray lpTokenHeld?: Balance.Amount - // primary token price in terms of sell/buy token - ptPrices: { - sell?: Balance.Quantity - buy?: Balance.Quantity - } getMaybeLimitPrice: () => Balance.Quantity | undefined getCalculatedPool: () => SwapOrderCalculation | undefined } @@ -219,10 +214,6 @@ export const defaultSwapState: SwapState = { calculations: [] as const, lpTokenHeld: undefined, - ptPrices: { - sell: '0', - buy: '0', - }, pools: [] as const, getMaybeLimitPrice: function () { return this.type === 'limit' ? this.limitPrice : undefined @@ -277,7 +268,6 @@ const orderReducer = ( amounts: state.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -316,7 +306,6 @@ const orderReducer = ( amounts: state.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: action.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -336,7 +325,6 @@ const orderReducer = ( amounts: draft.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -382,7 +370,6 @@ const orderReducer = ( amounts: draft.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -405,7 +392,6 @@ const orderReducer = ( amounts: state.orderData.amounts, limitPrice: action.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -431,7 +417,6 @@ const orderReducer = ( amounts: draft.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -457,7 +442,6 @@ const orderReducer = ( amounts: draft.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -484,7 +468,6 @@ const orderReducer = ( amounts: draft.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: draft.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -504,7 +487,6 @@ const orderReducer = ( amounts: draft.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: draft.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, @@ -523,7 +505,6 @@ const orderReducer = ( amounts: state.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: state.orderData.pools, primaryTokenId: '', lpTokenHeld: action.amount, @@ -540,7 +521,6 @@ const orderReducer = ( amounts: state.orderData.amounts, limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, - ptPrices: state.orderData.ptPrices, pools: draft.orderData.pools, primaryTokenId: '', lpTokenHeld: state.orderData.lpTokenHeld, From 790a9f29535b689e52a375d16690a5931bb32db8 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Sun, 8 Oct 2023 23:38:40 +0100 Subject: [PATCH 28/67] chore: clean state --- .../SelectBuyTokenFromListScreen.tsx | 16 +- packages/swap/src/helpers/mocks.ts | 1551 +++++++++++++++++ .../src/helpers/orders/getBestBuyPool.test.ts | 279 --- .../helpers/orders/getBestSellPool.test.ts | 281 --- .../helpers/orders/makeOrderCalculations.ts | 56 +- .../src/helpers/pools/getBestBuyPool.test.ts | 59 + .../{orders => pools}/getBestBuyPool.ts | 4 +- .../pools/getBestPoolCalculation.test.ts | 12 + .../helpers/pools/getBestPoolCalculation.ts | 25 + .../src/helpers/pools/getBestSellPool.test.ts | 61 + .../{orders => pools}/getBestSellPool.ts | 4 +- .../reactjs/provider/SwapProvider.test.tsx | 13 + .../reactjs/provider/SwapProvider.tsx | 17 +- .../selectors/limitPriceSelector.test.ts | 27 + .../state/selectors/limitPriceSelector.ts | 7 + .../selectedPoolCalculationSelector.test.ts | 71 + .../selectedPoolCalculationSelector.ts | 16 + .../translators/reactjs/state/state.test.ts | 332 ++-- .../src/translators/reactjs/state/state.ts | 368 ++-- 19 files changed, 2295 insertions(+), 904 deletions(-) create mode 100644 packages/swap/src/helpers/mocks.ts delete mode 100644 packages/swap/src/helpers/orders/getBestBuyPool.test.ts delete mode 100644 packages/swap/src/helpers/orders/getBestSellPool.test.ts create mode 100644 packages/swap/src/helpers/pools/getBestBuyPool.test.ts rename packages/swap/src/helpers/{orders => pools}/getBestBuyPool.ts (92%) create mode 100644 packages/swap/src/helpers/pools/getBestPoolCalculation.test.ts create mode 100644 packages/swap/src/helpers/pools/getBestPoolCalculation.ts create mode 100644 packages/swap/src/helpers/pools/getBestSellPool.test.ts rename packages/swap/src/helpers/{orders => pools}/getBestSellPool.ts (92%) create mode 100644 packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.test.ts create mode 100644 packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.ts create mode 100644 packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.test.ts create mode 100644 packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.ts diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 817c4a84c5..114b156614 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -1,5 +1,5 @@ import {FlashList} from '@shopify/flash-list' -import {useSwap, useSwapTokensByPairToken} from '@yoroi/swap' +import {useSwap, useSwapPoolsByPair, useSwapTokensByPairToken} from '@yoroi/swap' import {Balance} from '@yoroi/types' import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' @@ -178,8 +178,20 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenForList: TokenForList; wallet: YoroiWallet} const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {buyTokenIdChanged} = useSwap() + const {buyTokenIdChanged, orderData} = useSwap() const {buyTouched} = useSwapTouched() + const {refetch} = useSwapPoolsByPair( + { + tokenA: orderData.amounts.buy.tokenId, + tokenB: orderData.amounts.sell.tokenId, + }, + { + enabled: false, + }, + ) + React.useEffect(() => { + console.log('refetch') + }, [refetch, orderData.amounts.buy.tokenId]) const navigateTo = useNavigateTo() const balanceAvailable = useBalance({wallet, tokenId: tokenForList.id}) diff --git a/packages/swap/src/helpers/mocks.ts b/packages/swap/src/helpers/mocks.ts new file mode 100644 index 0000000000..2092fb7cde --- /dev/null +++ b/packages/swap/src/helpers/mocks.ts @@ -0,0 +1,1551 @@ +import {Swap} from '@yoroi/types' +import {SwapOrderCalculation} from 'translators/reactjs/state/state' + +const mockedPools1: Swap.Pool[] = [ + { + tokenA: {quantity: '529504614', tokenId: 'tokenA'}, + tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'muesliswap_v2', + price: 0, + batcherFee: {quantity: '950000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '1', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '143610201719', tokenId: 'tokenA'}, + tokenB: {quantity: '2055821866531', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'vyfi', + price: 0, + batcherFee: {quantity: '1900000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '2', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '27344918300893', tokenId: 'tokenA'}, + tokenB: {quantity: '393223050468514', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'minswap', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '3', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '3400529909', tokenId: 'tokenA'}, + tokenB: {quantity: '49215467634', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.35', // 0.35% + provider: 'wingriders', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '4', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '10178222382', tokenId: 'tokenA'}, + tokenB: {quantity: '145009426744', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '5', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '973669994', tokenId: 'tokenA'}, + tokenB: {quantity: '13710853133', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.05', // 0.05% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '6', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, +] + +const mockedPools2: Swap.Pool[] = [ + { + tokenA: {quantity: '529504614', tokenId: 'tokenA'}, + tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'muesliswap_v2', + price: 0, + batcherFee: {quantity: '950000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + + { + tokenA: {quantity: '143610201719', tokenId: 'tokenA'}, + tokenB: {quantity: '2055821866531', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'vyfi', + price: 0, + batcherFee: {quantity: '1900000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + + { + tokenA: {quantity: '27344918300893', tokenId: 'tokenA'}, + tokenB: {quantity: '393223050468514', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'minswap', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + + { + tokenA: {quantity: '3400529909', tokenId: 'tokenA'}, + tokenB: {quantity: '49215467634', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.35', // 0.35% + provider: 'wingriders', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + + { + tokenA: {quantity: '10178222382', tokenId: 'tokenA'}, + tokenB: {quantity: '145009426744', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', // 0.3% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + + { + tokenA: {quantity: '973669994', tokenId: 'tokenA'}, + tokenB: {quantity: '13710853133', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.05', // 0.05% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, +] +const mockedPools3: Swap.Pool[] = [ + { + tokenA: {quantity: '529504614', tokenId: 'tokenA'}, + tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'muesliswap_v2', + price: 0, + batcherFee: {quantity: '950000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '143610201719', tokenId: 'tokenA'}, + tokenB: {quantity: '2055821866531', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'vyfi', + price: 0, + batcherFee: {quantity: '1900000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '27337840212697', tokenId: 'tokenA'}, + tokenB: {quantity: '393349086430693', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'minswap', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '3400529909', tokenId: 'tokenA'}, + tokenB: {quantity: '49215467634', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.35', // 0.35% + provider: 'wingriders', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '10178222382', tokenId: 'tokenA'}, + tokenB: {quantity: '145009426744', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenA: {quantity: '973669994', tokenId: 'tokenA'}, + tokenB: {quantity: '13710853133', tokenId: 'tokenB'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.05', // 0.05% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, +] +const mockedPools4: Swap.Pool[] = [ + { + tokenB: {quantity: '529504614', tokenId: 'tokenB'}, + tokenA: {quantity: '7339640354', tokenId: 'tokenA'}, + ptPriceTokenB: '1', + ptPriceTokenA: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'muesliswap_v2', + price: 0, + batcherFee: {quantity: '950000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenB: {quantity: '143610201719', tokenId: 'tokenB'}, + tokenA: {quantity: '2055821866531', tokenId: 'tokenA'}, + ptPriceTokenB: '1', + ptPriceTokenA: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'vyfi', + price: 0, + batcherFee: {quantity: '1900000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenB: {quantity: '27337840212697', tokenId: 'tokenB'}, + tokenA: {quantity: '393349086430693', tokenId: 'tokenA'}, + ptPriceTokenB: '1', + ptPriceTokenA: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'minswap', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenB: {quantity: '3400529909', tokenId: 'tokenB'}, + tokenA: {quantity: '49215467634', tokenId: 'tokenA'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.35', // 0.35% + provider: 'wingriders', + price: 0, + batcherFee: {quantity: '2000000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenB: {quantity: '10178222382', tokenId: 'tokenB'}, + tokenA: {quantity: '145009426744', tokenId: 'tokenA'}, + ptPriceTokenB: '1', + ptPriceTokenA: '0.06950020009', + fee: '0.3', // 0.3% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + { + tokenB: {quantity: '973669994', tokenId: 'tokenB'}, + tokenA: {quantity: '13710853133', tokenId: 'tokenA'}, + ptPriceTokenA: '1', + ptPriceTokenB: '0.06950020009', + fee: '0.05', // 0.05% + provider: 'sundaeswap', + price: 0, + batcherFee: {quantity: '2500000', tokenId: ''}, + deposit: {quantity: '2000000', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, +] + +const mockedOrderCalculations1: SwapOrderCalculation[] = [ + { + order: { + side: 'sell', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + buy: { + quantity: '0', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '1162995513', + tokenId: 'tokenB', + }, + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '950000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '1050000', + }, + discountTier: { + primaryTokenValueThreshold: '100000000', + secondaryTokenBalanceThreshold: '0', + variableFeeMultiplier: 0.0005, + variableFeeVisual: 0.05, + fixedFee: '1000000', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '300000', + }, + }, + buyAmountWithSlippage: { + quantity: '1046695961', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.07214312806368332309', + market: '0.07214312806368332309', + withSlippage: '0.09553872731529533436', + withFees: '0.08770455161678684826', + withFeesAndSlippage: '0.09744950186160124105', + difference: '21.570209070179074072', + withFeesNoFEF: '0.08680171064426110129', + withFeesAndSlippageNoFEF: '0.09644634522479064004', + differenceNoFEF: '20.318751035633113011', + }, + pool: { + tokenA: { + quantity: '529504614', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '7339640354', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'muesliswap_v2', + price: 0, + batcherFee: { + quantity: '950000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '1', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'sell', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + buy: { + quantity: '0', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '1426244382', + tokenId: 'tokenB', + }, + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '1900000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '1050000', + }, + discountTier: { + primaryTokenValueThreshold: '100000000', + secondaryTokenBalanceThreshold: '0', + variableFeeMultiplier: 0.0005, + variableFeeVisual: 0.05, + fixedFee: '1000000', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '300000', + }, + }, + buyAmountWithSlippage: { + quantity: '1283619943', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.06985537222703457584', + market: '0.06985537222703457584', + withSlippage: '0.07790467929805294401', + withFees: '0.07218258055862406896', + withFeesAndSlippage: '0.08020286733734550586', + difference: '3.33146651058691987', + withFeesNoFEF: '0.07144638133971629555', + withFeesAndSlippageNoFEF: '0.07938486820471594995', + differenceNoFEF: '2.277575885661069787', + }, + pool: { + tokenA: { + quantity: '143610201719', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '2055821866531', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'vyfi', + price: 0, + batcherFee: { + quantity: '1900000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '2', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'sell', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + buy: { + quantity: '0', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '1433692167', + tokenId: 'tokenB', + }, + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '1050000', + }, + discountTier: { + primaryTokenValueThreshold: '100000000', + secondaryTokenBalanceThreshold: '0', + variableFeeMultiplier: 0.0005, + variableFeeVisual: 0.05, + fixedFee: '1000000', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '300000', + }, + }, + buyAmountWithSlippage: { + quantity: '1290322950', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.06954047650134526242', + market: '0.06954047650134526242', + withSlippage: '0.07749997781563135028', + withFees: '0.0718773544083958157', + withFeesAndSlippage: '0.07986372713900810646', + difference: '3.360457138951796387', + withFeesNoFEF: '0.07114497961820837653', + withFeesAndSlippageNoFEF: '0.07904997737194397728', + differenceNoFEF: '2.307293820214296279', + }, + pool: { + tokenA: { + quantity: '27344918300893', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '393223050468514', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'minswap', + price: 0, + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '3', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'sell', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + buy: { + quantity: '0', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '1401162647', + tokenId: 'tokenB', + }, + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '1050000', + }, + discountTier: { + primaryTokenValueThreshold: '100000000', + secondaryTokenBalanceThreshold: '0', + variableFeeMultiplier: 0.0005, + variableFeeVisual: 0.05, + fixedFee: '1000000', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '350000', + }, + }, + buyAmountWithSlippage: { + quantity: '1261046382', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.06909473936707611128', + market: '0.06909473936707611128', + withSlippage: '0.07929922438015448031', + withFees: '0.07354606563387783488', + withFeesAndSlippage: '0.08171785072374919196', + difference: '6.44235191792733844', + withFeesNoFEF: '0.07279668796366365025', + withFeesAndSlippageNoFEF: '0.08088520886775756992', + differenceNoFEF: '5.357786468981936163', + }, + pool: { + tokenA: { + quantity: '3400529909', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '49215467634', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.35', + provider: 'wingriders', + price: 0, + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '4', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'sell', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + buy: { + quantity: '0', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '1406650031', + tokenId: 'tokenB', + }, + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '1050000', + }, + discountTier: { + primaryTokenValueThreshold: '100000000', + secondaryTokenBalanceThreshold: '0', + variableFeeMultiplier: 0.0005, + variableFeeVisual: 0.05, + fixedFee: '1000000', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '300000', + }, + }, + buyAmountWithSlippage: { + quantity: '1265985027', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.07019007391821953012', + market: '0.07019007391821953012', + withSlippage: '0.07898987576256697703', + withFees: '0.07361461466459101084', + withFeesAndSlippage: '0.08179401635213810471', + difference: '4.878953041653028379', + withFeesNoFEF: '0.07286816033916541392', + withFeesAndSlippageNoFEF: '0.08096462265663115145', + differenceNoFEF: '3.81547741930888855', + }, + pool: { + tokenA: { + quantity: '10178222382', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '145009426744', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'sundaeswap', + price: 0, + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '5', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'sell', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + buy: { + quantity: '0', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '1276429070', + tokenId: 'tokenB', + }, + sell: { + quantity: '100000000', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '1050000', + }, + discountTier: { + primaryTokenValueThreshold: '100000000', + secondaryTokenBalanceThreshold: '0', + variableFeeMultiplier: 0.0005, + variableFeeVisual: 0.05, + fixedFee: '1000000', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '50000', + }, + }, + buyAmountWithSlippage: { + quantity: '1148786163', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.07101454479564951518', + market: '0.07101454479564951518', + withSlippage: '0.08704840223602170946', + withFees: '0.08112475846386043214', + withFeesAndSlippage: '0.09013862051540048015', + difference: '14.236821058705550837', + withFeesNoFEF: '0.08030215106273002698', + withFeesAndSlippageNoFEF: '0.0892246122919222522', + differenceNoFEF: '13.078456383556918976', + }, + pool: { + tokenA: { + quantity: '973669994', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '13710853133', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.05', + provider: 'sundaeswap', + price: 0, + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '6', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, +] + +const mockedOrderCalculations2: SwapOrderCalculation[] = [ + { + order: { + side: 'buy', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '0', + tokenId: 'tokenA', + }, + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + sell: { + quantity: '7335973', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '950000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '0', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '22008', + }, + }, + buyAmountWithSlippage: { + quantity: '90000000', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.07214312806368332309', + market: '0.07214312806368332309', + withSlippage: '0.08151081111111111111', + withFees: '0.08285972917140270829', + withFeesAndSlippage: '0.09206636666666666667', + difference: '14.854638820567161388', + withFeesNoFEF: '0.08285972917140270829', + withFeesAndSlippageNoFEF: '0.09206636666666666667', + differenceNoFEF: '14.854638820567161388', + }, + pool: { + tokenA: { + quantity: '529504614', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '7339640354', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'muesliswap_v2', + price: 0, + batcherFee: { + quantity: '950000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '1', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'buy', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '0', + tokenId: 'tokenA', + }, + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + sell: { + quantity: '7006900', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '1900000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '0', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '21021', + }, + }, + buyAmountWithSlippage: { + quantity: '90000000', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.06985537222703457584', + market: '0.06985537222703457584', + withSlippage: '0.07785444444444444444', + withFees: '0.08906899910931000891', + withFeesAndSlippage: '0.09896555555555555556', + difference: '27.50486651166910406', + withFeesNoFEF: '0.08906899910931000891', + withFeesAndSlippageNoFEF: '0.09896555555555555556', + differenceNoFEF: '27.50486651166910406', + }, + pool: { + tokenA: { + quantity: '143610201719', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '2055821866531', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'vyfi', + price: 0, + batcherFee: { + quantity: '1900000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '2', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'buy', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '0', + tokenId: 'tokenA', + }, + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + sell: { + quantity: '6974976', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '0', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '20925', + }, + }, + buyAmountWithSlippage: { + quantity: '90000000', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.06954047650134526242', + market: '0.06954047650134526242', + withSlippage: '0.07749973333333333333', + withFees: '0.08974975910250240897', + withFeesAndSlippage: '0.09972195555555555556', + difference: '29.061179356121031793', + withFeesNoFEF: '0.08974975910250240897', + withFeesAndSlippageNoFEF: '0.09972195555555555556', + differenceNoFEF: '29.061179356121031793', + }, + pool: { + tokenA: { + quantity: '27344918300893', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '393223050468514', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'minswap', + price: 0, + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '3', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'buy', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '0', + tokenId: 'tokenA', + }, + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + sell: { + quantity: '6947861', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '0', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '24318', + }, + }, + buyAmountWithSlippage: { + quantity: '90000000', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.06909473936707611128', + market: '0.06909473936707611128', + withSlippage: '0.07719845555555555556', + withFees: '0.08947860910521390895', + withFeesAndSlippage: '0.09942067777777777778', + difference: '29.501333856757818526', + withFeesNoFEF: '0.08947860910521390895', + withFeesAndSlippageNoFEF: '0.09942067777777777778', + differenceNoFEF: '29.501333856757818526', + }, + pool: { + tokenA: { + quantity: '3400529909', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '49215467634', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.35', + provider: 'wingriders', + price: 0, + batcherFee: { + quantity: '2000000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '4', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'buy', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '0', + tokenId: 'tokenA', + }, + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + sell: { + quantity: '7044988', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '0', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '21135', + }, + }, + buyAmountWithSlippage: { + quantity: '90000000', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.07019007391821953012', + market: '0.07019007391821953012', + withSlippage: '0.07827764444444444444', + withFees: '0.09544987904550120954', + withFeesAndSlippage: '0.10605542222222222222', + difference: '35.987716948001227979', + withFeesNoFEF: '0.09544987904550120954', + withFeesAndSlippageNoFEF: '0.10605542222222222222', + differenceNoFEF: '35.987716948001227979', + }, + pool: { + tokenA: { + quantity: '10178222382', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '145009426744', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.3', + provider: 'sundaeswap', + price: 0, + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '5', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, + { + order: { + side: 'buy', + slippage: 10, + orderType: 'market', + amounts: { + sell: { + quantity: '0', + tokenId: 'tokenA', + }, + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + }, + }, + sides: { + buy: { + quantity: '100000001', + tokenId: 'tokenB', + }, + sell: { + quantity: '7157210', + tokenId: 'tokenA', + }, + }, + cost: { + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + frontendFeeInfo: { + fee: { + tokenId: '', + quantity: '0', + }, + }, + liquidityFee: { + tokenId: 'tokenA', + quantity: '3579', + }, + }, + buyAmountWithSlippage: { + quantity: '90000000', + tokenId: 'tokenB', + }, + hasSupply: true, + prices: { + base: '0.07101454479564951518', + market: '0.07101454479564951518', + withSlippage: '0.07952455555555555556', + withFees: '0.09657209903427900966', + withFeesAndSlippage: '0.10730233333333333333', + difference: '35.989182655713084861', + withFeesNoFEF: '0.09657209903427900966', + withFeesAndSlippageNoFEF: '0.10730233333333333333', + differenceNoFEF: '35.989182655713084861', + }, + pool: { + tokenA: { + quantity: '973669994', + tokenId: 'tokenA', + }, + tokenB: { + quantity: '13710853133', + tokenId: 'tokenB', + }, + ptPriceTokenA: '1', + ptPriceTokenB: '0.0695404765', + fee: '0.05', + provider: 'sundaeswap', + price: 0, + batcherFee: { + quantity: '2500000', + tokenId: '', + }, + deposit: { + quantity: '2000000', + tokenId: '', + }, + poolId: '6', + lpToken: { + quantity: '0', + tokenId: '0', + }, + }, + }, +] + +export const mocks = { + mockedPools1, + mockedPools2, + mockedPools3, + mockedPools4, + + mockedOrderCalculations1, + mockedOrderCalculations2, +} diff --git a/packages/swap/src/helpers/orders/getBestBuyPool.test.ts b/packages/swap/src/helpers/orders/getBestBuyPool.test.ts deleted file mode 100644 index 0a7eace89c..0000000000 --- a/packages/swap/src/helpers/orders/getBestBuyPool.test.ts +++ /dev/null @@ -1,279 +0,0 @@ -import {Swap, Balance} from '@yoroi/types' - -import {getBestBuyPool} from './getBestBuyPool' -import {getBuyAmount} from './getBuyAmount' - -describe('getBestBuyPool', () => { - it('should return pool with maximin possible tokens to buy', () => { - const pool1: Swap.Pool = { - tokenA: {quantity: '529504614', tokenId: 'tokenA'}, - tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'muesliswap_v2', - price: 0, - batcherFee: {quantity: '950000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool2: Swap.Pool = { - tokenA: {quantity: '143610201719', tokenId: 'tokenA'}, - tokenB: {quantity: '2055821866531', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'vyfi', - price: 0, - batcherFee: {quantity: '1900000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool3: Swap.Pool = { - tokenA: {quantity: '27344918300893', tokenId: 'tokenA'}, - tokenB: {quantity: '393223050468514', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'minswap', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool4: Swap.Pool = { - tokenA: {quantity: '3400529909', tokenId: 'tokenA'}, - tokenB: {quantity: '49215467634', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.35', // 0.35% - provider: 'wingriders', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool5: Swap.Pool = { - tokenA: {quantity: '10178222382', tokenId: 'tokenA'}, - tokenB: {quantity: '145009426744', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool6: Swap.Pool = { - tokenA: {quantity: '973669994', tokenId: 'tokenA'}, - tokenB: {quantity: '13710853133', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.05', // 0.05% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } as Swap.Pool - - const sell: Balance.Amount = { - quantity: '10000000000', - tokenId: 'tokenB', - } - - const pools = [pool1, pool2, pool3, pool4, pool5, pool6] - const bestBuyPool = getBestBuyPool(pools, sell) - if (bestBuyPool) { - expect(bestBuyPool.provider).toBe('minswap') - const buyAmount = getBuyAmount(bestBuyPool, sell) - expect(buyAmount.quantity).toBe('693300972') - } else { - fail('bestBuyPool undefined') - } - }) - - it('should return pool with maximin possible tokens to buy (case 2)', () => { - const pool1: Swap.Pool = { - tokenA: {quantity: '529504614', tokenId: 'tokenA'}, - tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'muesliswap_v2', - price: 0, - batcherFee: {quantity: '950000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool2: Swap.Pool = { - tokenA: {quantity: '143610201719', tokenId: 'tokenA'}, - tokenB: {quantity: '2055821866531', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'vyfi', - price: 0, - batcherFee: {quantity: '1900000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool3: Swap.Pool = { - tokenA: {quantity: '27344918300893', tokenId: 'tokenA'}, - tokenB: {quantity: '393223050468514', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'minswap', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool4: Swap.Pool = { - tokenA: {quantity: '3400529909', tokenId: 'tokenA'}, - tokenB: {quantity: '49215467634', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.35', // 0.35% - provider: 'wingriders', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool5: Swap.Pool = { - tokenA: {quantity: '10178222382', tokenId: 'tokenA'}, - tokenB: {quantity: '145009426744', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool6: Swap.Pool = { - tokenA: {quantity: '973669994', tokenId: 'tokenA'}, - tokenB: {quantity: '13710853133', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.05', // 0.05% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } as Swap.Pool - - const sell: Balance.Amount = { - quantity: '1000000000', - tokenId: 'tokenA', - } - - const pools = [pool1, pool2, pool3, pool4, pool5, pool6] - const bestBuyPool = getBestBuyPool(pools, sell) - if (bestBuyPool) { - expect(bestBuyPool.provider).toBe('minswap') - const buyAmount = getBuyAmount(bestBuyPool, sell) - expect(buyAmount.quantity).toBe('14336451239') - } else { - fail('bestBuyPool undefined') - } - }) - - it('should return undefined if sell amount is 0', () => { - const pool1: Swap.Pool = { - tokenA: {quantity: '529504614', tokenId: 'tokenA'}, - tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'muesliswap_v2', - price: 0, - batcherFee: {quantity: '950000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const sell: Balance.Amount = { - quantity: '0', - tokenId: 'tokenA', - } - - expect(getBestBuyPool([pool1], sell)).toBeUndefined() - }) - - it('should return undefined if pools list is empty', () => { - const sell: Balance.Amount = { - quantity: '1', - tokenId: 'tokenA', - } - - expect(getBestBuyPool([], sell)).toBeUndefined() - }) -}) diff --git a/packages/swap/src/helpers/orders/getBestSellPool.test.ts b/packages/swap/src/helpers/orders/getBestSellPool.test.ts deleted file mode 100644 index c98692a907..0000000000 --- a/packages/swap/src/helpers/orders/getBestSellPool.test.ts +++ /dev/null @@ -1,281 +0,0 @@ -import {Swap, Balance} from '@yoroi/types' - -import {getBestSellPool} from './getBestSellPool' -import {getSellAmount} from './getSellAmount' - -describe('getBestSellPool', () => { - it('should return pool with min possible tokens to sell', () => { - const pool1: Swap.Pool = { - tokenA: {quantity: '529504614', tokenId: 'tokenA'}, - tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'muesliswap_v2', - price: 0, - batcherFee: {quantity: '950000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool2: Swap.Pool = { - tokenA: {quantity: '143610201719', tokenId: 'tokenA'}, - tokenB: {quantity: '2055821866531', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'vyfi', - price: 0, - batcherFee: {quantity: '1900000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool3: Swap.Pool = { - tokenA: {quantity: '27337840212697', tokenId: 'tokenA'}, - tokenB: {quantity: '393349086430693', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'minswap', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool4: Swap.Pool = { - tokenA: {quantity: '3400529909', tokenId: 'tokenA'}, - tokenB: {quantity: '49215467634', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.35', // 0.35% - provider: 'wingriders', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool5: Swap.Pool = { - tokenA: {quantity: '10178222382', tokenId: 'tokenA'}, - tokenB: {quantity: '145009426744', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool6: Swap.Pool = { - tokenA: {quantity: '973669994', tokenId: 'tokenA'}, - tokenB: {quantity: '13710853133', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.05', // 0.05% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } as Swap.Pool - - const buy: Balance.Amount = { - quantity: '1000000000', - tokenId: 'tokenB', - } - - const pools = [pool1, pool2, pool3, pool4, pool5, pool6] - const bestSellPool = getBestSellPool(pools, buy) - - if (bestSellPool) { - expect(bestSellPool.provider).toBe('minswap') - const sellAmount = getSellAmount(bestSellPool, buy) - expect(sellAmount.quantity).toBe('69709507') - } else { - fail('bestSellPool is undefined') - } - }) - - it('should return pool with min possible tokens to sell (opposite test)', () => { - const pool1: Swap.Pool = { - tokenB: {quantity: '529504614', tokenId: 'tokenB'}, - tokenA: {quantity: '7339640354', tokenId: 'tokenA'}, - ptPriceTokenB: '1', - ptPriceTokenA: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'muesliswap_v2', - price: 0, - batcherFee: {quantity: '950000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool2: Swap.Pool = { - tokenB: {quantity: '143610201719', tokenId: 'tokenB'}, - tokenA: {quantity: '2055821866531', tokenId: 'tokenA'}, - ptPriceTokenB: '1', - ptPriceTokenA: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'vyfi', - price: 0, - batcherFee: {quantity: '1900000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool3: Swap.Pool = { - tokenB: {quantity: '27337840212697', tokenId: 'tokenB'}, - tokenA: {quantity: '393349086430693', tokenId: 'tokenA'}, - ptPriceTokenB: '1', - ptPriceTokenA: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'minswap', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool4: Swap.Pool = { - tokenB: {quantity: '3400529909', tokenId: 'tokenB'}, - tokenA: {quantity: '49215467634', tokenId: 'tokenA'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.35', // 0.35% - provider: 'wingriders', - price: 0, - batcherFee: {quantity: '2000000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool5: Swap.Pool = { - tokenB: {quantity: '10178222382', tokenId: 'tokenB'}, - tokenA: {quantity: '145009426744', tokenId: 'tokenA'}, - ptPriceTokenB: '1', - ptPriceTokenA: '0.06950020009', - fee: '0.3', // 0.3% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const pool6: Swap.Pool = { - tokenB: {quantity: '973669994', tokenId: 'tokenB'}, - tokenA: {quantity: '13710853133', tokenId: 'tokenA'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.06950020009', - fee: '0.05', // 0.05% - provider: 'sundaeswap', - price: 0, - batcherFee: {quantity: '2500000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } as Swap.Pool - - const buy: Balance.Amount = { - quantity: '1000000000', - tokenId: 'tokenA', - } - - const pools = [pool1, pool2, pool3, pool4, pool5, pool6] - const bestSellPool = getBestSellPool(pools, buy) - - if (bestSellPool) { - expect(bestSellPool.provider).toBe('minswap') - const sellAmount = getSellAmount(bestSellPool, buy) - expect(sellAmount.quantity).toBe('69709507') - } else { - fail('bestSellPool is undefined') - } - }) - - it('should return undefined if buy amount is 0', () => { - const pool1: Swap.Pool = { - tokenA: {quantity: '529504614', tokenId: 'tokenA'}, - tokenB: {quantity: '7339640354', tokenId: 'tokenB'}, - ptPriceTokenA: '1', - ptPriceTokenB: '0.0695404765', - fee: '0.3', // 0.3% - provider: 'muesliswap_v2', - price: 0, - batcherFee: {quantity: '950000', tokenId: ''}, - deposit: {quantity: '2000000', tokenId: ''}, - poolId: '0', - lpToken: { - quantity: '0', - tokenId: '0', - }, - } - - const sell: Balance.Amount = { - quantity: '0', - tokenId: 'tokenA', - } - - expect(getBestSellPool([pool1], sell)).toBeUndefined() - }) - - it('should return undefined if pools list is empty', () => { - const sell: Balance.Amount = { - quantity: '1', - tokenId: 'tokenA', - } - - expect(getBestSellPool([], sell)).toBeUndefined() - }) -}) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 4a92014d28..648eb4fafc 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -18,7 +18,7 @@ export const makeOrderCalculations = ({ pools, primaryTokenId, lpTokenHeld, - action, + side, }: Readonly<{ orderType: Swap.OrderType amounts: { @@ -30,24 +30,24 @@ export const makeOrderCalculations = ({ lpTokenHeld?: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] - action?: 'buy' | 'sell' + side?: 'buy' | 'sell' }>): Array => { const isLimit = orderType === 'limit' const maybeLimitPrice = isLimit ? limitPrice : undefined - return pools.map((pool) => { + const calculations = pools.map((pool) => { const buy = - action === 'sell' + side === 'sell' ? getBuyAmount(pool, amounts.sell, maybeLimitPrice) : amounts.buy const sell = - action === 'buy' + side === 'buy' ? getSellAmount(pool, amounts.buy, maybeLimitPrice) : amounts.sell const marketPrice = getMarketPrice(pool, sell) // recalculate price base, limit is user's input, market from pool - const priceBase = isLimit ? limitPrice ?? marketPrice : marketPrice + const priceBase = maybeLimitPrice ?? marketPrice // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { @@ -113,7 +113,11 @@ export const makeOrderCalculations = ({ .toString(), ) - const calculatePricesWithFees = (withFrontendFee?: boolean) => { + const calculatePricesWithFees = ({ + withFrontendFee, + }: { + withFrontendFee?: boolean + }) => { // add up all that's being sold in sell terms const sellWithBatcher = new BigNumber(sell.quantity).plus( feeInSellSideQuantities.batcherFee, @@ -133,11 +137,13 @@ export const makeOrderCalculations = ({ : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() // always based, if is limit it can lead to a weird percentage - const priceDifference = priceWithFees - .minus(priceBase) - .dividedBy(priceBase) - .times(100) - .toString() + const priceDifference = Quantities.isZero(priceBase) + ? Quantities.zero + : priceWithFees + .minus(priceBase) + .dividedBy(priceBase) + .times(100) + .toString() return { priceWithFees: asQuantity(priceWithFees), @@ -146,17 +152,31 @@ export const makeOrderCalculations = ({ } } + // fees + ffee + slippage const { priceWithFees: withFees, priceWithFeesAndSlippage: withFeesAndSlippage, priceDifference: difference, - } = calculatePricesWithFees(true) + } = calculatePricesWithFees({withFrontendFee: true}) const { priceWithFees: withFeesNoFEF, priceWithFeesAndSlippage: withFeesAndSlippageNoFEF, priceDifference: differenceNoFEF, - } = calculatePricesWithFees(false) - return { + } = calculatePricesWithFees({withFrontendFee: false}) + + const result: SwapOrderCalculation = { + order: { + side, + slippage, + orderType, + limitPrice, + amounts, + lpTokenHeld, + }, + sides: { + buy, + sell, + }, cost: { batcherFee: pool.batcherFee, deposit: pool.deposit, @@ -177,6 +197,10 @@ export const makeOrderCalculations = ({ differenceNoFEF, }, pool, - } + } as const + + return result }) + + return calculations } diff --git a/packages/swap/src/helpers/pools/getBestBuyPool.test.ts b/packages/swap/src/helpers/pools/getBestBuyPool.test.ts new file mode 100644 index 0000000000..525c6b802e --- /dev/null +++ b/packages/swap/src/helpers/pools/getBestBuyPool.test.ts @@ -0,0 +1,59 @@ +import {Balance} from '@yoroi/types' + +import {getBestBuyPool} from './getBestBuyPool' +import {getBuyAmount} from '../orders/getBuyAmount' +import {mocks} from '../mocks' + +describe('getBestBuyPool', () => { + it('should return pool with maximin possible tokens to buy', () => { + const sell: Balance.Amount = { + quantity: '10000000000', + tokenId: 'tokenB', + } + + const pools = mocks.mockedPools1 + const bestBuyPool = getBestBuyPool(pools, sell) + if (bestBuyPool) { + expect(bestBuyPool.provider).toBe('minswap') + const buyAmount = getBuyAmount(bestBuyPool, sell) + expect(buyAmount.quantity).toBe('693300972') + } else { + fail('bestBuyPool undefined') + } + }) + + it('should return pool with maximin possible tokens to buy (case 2)', () => { + const sell: Balance.Amount = { + quantity: '1000000000', + tokenId: 'tokenA', + } + + const pools = mocks.mockedPools2 + const bestBuyPool = getBestBuyPool(pools, sell) + if (bestBuyPool) { + expect(bestBuyPool.provider).toBe('minswap') + const buyAmount = getBuyAmount(bestBuyPool, sell) + expect(buyAmount.quantity).toBe('14336451239') + } else { + fail('bestBuyPool undefined') + } + }) + + it('should return undefined if sell amount is 0', () => { + const sell: Balance.Amount = { + quantity: '0', + tokenId: 'tokenA', + } + + expect(getBestBuyPool([mocks.mockedPools1[0]!], sell)).toBeUndefined() + }) + + it('should return undefined if pools list is empty', () => { + const sell: Balance.Amount = { + quantity: '1', + tokenId: 'tokenA', + } + + expect(getBestBuyPool([], sell)).toBeUndefined() + }) +}) diff --git a/packages/swap/src/helpers/orders/getBestBuyPool.ts b/packages/swap/src/helpers/pools/getBestBuyPool.ts similarity index 92% rename from packages/swap/src/helpers/orders/getBestBuyPool.ts rename to packages/swap/src/helpers/pools/getBestBuyPool.ts index 018a6d593a..56a70f66c7 100644 --- a/packages/swap/src/helpers/orders/getBestBuyPool.ts +++ b/packages/swap/src/helpers/pools/getBestBuyPool.ts @@ -1,8 +1,8 @@ import {Balance, Swap} from '@yoroi/types' import {Quantities} from '../../utils/quantities' -import {getBuyAmount} from './getBuyAmount' -import {getPriceAfterFee} from './getPriceAfterFee' +import {getBuyAmount} from '../orders/getBuyAmount' +import {getPriceAfterFee} from '../orders/getPriceAfterFee' import BigNumber from 'bignumber.js' /** diff --git a/packages/swap/src/helpers/pools/getBestPoolCalculation.test.ts b/packages/swap/src/helpers/pools/getBestPoolCalculation.test.ts new file mode 100644 index 0000000000..52f87e8ab9 --- /dev/null +++ b/packages/swap/src/helpers/pools/getBestPoolCalculation.test.ts @@ -0,0 +1,12 @@ +import {mocks} from '../mocks' +import {getBestPoolCalculation} from './getBestPoolCalculation' + +describe('getBestPoolCalculation', () => { + it('should return the best pool calculation', () => { + const bestCalculation = getBestPoolCalculation( + mocks.mockedOrderCalculations1, + ) + + expect(bestCalculation?.pool.poolId).toBe('3') + }) +}) diff --git a/packages/swap/src/helpers/pools/getBestPoolCalculation.ts b/packages/swap/src/helpers/pools/getBestPoolCalculation.ts new file mode 100644 index 0000000000..f76f616eea --- /dev/null +++ b/packages/swap/src/helpers/pools/getBestPoolCalculation.ts @@ -0,0 +1,25 @@ +import {Quantities} from '../../utils/quantities' +import {SwapOrderCalculation} from '../../translators/reactjs/state/state' + +export const getBestPoolCalculation = ( + calculations: ReadonlyArray, +): SwapOrderCalculation | undefined => { + return calculations.reduce( + ( + best: SwapOrderCalculation | undefined, + current, + ): SwapOrderCalculation | undefined => { + if (!current.hasSupply) return best + + if (best === undefined) return current + + if ( + Quantities.isGreaterThan(best.prices.withFees, current.prices.withFees) + ) + return current + + return best + }, + undefined, + ) +} diff --git a/packages/swap/src/helpers/pools/getBestSellPool.test.ts b/packages/swap/src/helpers/pools/getBestSellPool.test.ts new file mode 100644 index 0000000000..2b636e5b59 --- /dev/null +++ b/packages/swap/src/helpers/pools/getBestSellPool.test.ts @@ -0,0 +1,61 @@ +import {Balance} from '@yoroi/types' + +import {getBestSellPool} from './getBestSellPool' +import {getSellAmount} from '../orders/getSellAmount' +import {mocks} from '../mocks' + +describe('getBestSellPool', () => { + it('should return pool with min possible tokens to sell', () => { + const buy: Balance.Amount = { + quantity: '1000000000', + tokenId: 'tokenB', + } + + const pools = mocks.mockedPools3 + const bestSellPool = getBestSellPool(pools, buy) + + if (bestSellPool) { + expect(bestSellPool.provider).toBe('minswap') + const sellAmount = getSellAmount(bestSellPool, buy) + expect(sellAmount.quantity).toBe('69709507') + } else { + fail('bestSellPool is undefined') + } + }) + + it('should return pool with min possible tokens to sell (opposite test)', () => { + const buy: Balance.Amount = { + quantity: '1000000000', + tokenId: 'tokenA', + } + + const pools = mocks.mockedPools4 + const bestSellPool = getBestSellPool(pools, buy) + + if (bestSellPool) { + expect(bestSellPool.provider).toBe('minswap') + const sellAmount = getSellAmount(bestSellPool, buy) + expect(sellAmount.quantity).toBe('69709507') + } else { + fail('bestSellPool is undefined') + } + }) + + it('should return undefined if buy amount is 0', () => { + const sell: Balance.Amount = { + quantity: '0', + tokenId: 'tokenA', + } + + expect(getBestSellPool([mocks.mockedPools4[0]!], sell)).toBeUndefined() + }) + + it('should return undefined if pools list is empty', () => { + const sell: Balance.Amount = { + quantity: '1', + tokenId: 'tokenA', + } + + expect(getBestSellPool([], sell)).toBeUndefined() + }) +}) diff --git a/packages/swap/src/helpers/orders/getBestSellPool.ts b/packages/swap/src/helpers/pools/getBestSellPool.ts similarity index 92% rename from packages/swap/src/helpers/orders/getBestSellPool.ts rename to packages/swap/src/helpers/pools/getBestSellPool.ts index 226d9c9c6d..83c6922bd4 100644 --- a/packages/swap/src/helpers/orders/getBestSellPool.ts +++ b/packages/swap/src/helpers/pools/getBestSellPool.ts @@ -2,8 +2,8 @@ import {Balance, Swap} from '@yoroi/types' import {Quantities} from '../../utils/quantities' import BigNumber from 'bignumber.js' -import {getPriceAfterFee} from './getPriceAfterFee' -import {getSellAmount} from './getSellAmount' +import {getPriceAfterFee} from '../orders/getPriceAfterFee' +import {getSellAmount} from '../orders/getSellAmount' /** * Find the best pool to sell based on the desired sell amount in a liquidity pool. diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx index 18a1a3572c..f448f950f1 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.test.tsx @@ -55,6 +55,19 @@ describe('SwapProvider', () => { ) }) + // initial state = market order + expect(result.current.orderData.selectedPoolId).toBeUndefined() + + act(() => { + result.current.orderTypeChanged('limit') + }) + + act(() => { + result.current.selectedPoolChanged( + swapManagerMocks.listPoolsByPairResponse[0]?.poolId!, + ) + }) + expect(result.current.orderData.selectedPoolId).toEqual( swapManagerMocks.listPoolsByPairResponse[0]?.poolId, ) diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx index 06bec69436..194d232c82 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx @@ -79,21 +79,18 @@ export const SwapProvider = ({ lpTokenHeldChanged: (amount: Balance.Amount | undefined) => { dispatch({type: SwapCreateOrderActionType.LpTokenHeldChanged, amount}) }, - buyTokenIdChanged: (payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - }) => { - dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, payload}) + buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { + dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, tokenId}) }, - sellTokenIdChanged: (payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - }) => { - dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, payload}) + sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { + dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, tokenId}) }, poolPairsChanged: (pools: ReadonlyArray) => { dispatch({type: SwapCreateOrderActionType.PoolPairsChanged, pools}) }, + primaryTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { + dispatch({type: SwapCreateOrderActionType.PrimaryTokenIdChanged, tokenId}) + }, }).current const context = React.useMemo( diff --git a/packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.test.ts b/packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.test.ts new file mode 100644 index 0000000000..47188d0707 --- /dev/null +++ b/packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.test.ts @@ -0,0 +1,27 @@ +import {limitPriceSelector} from './limitPriceSelector' // adjust the import path +import {SwapState} from '../state' // adjust the import path if needed +import {mockSwapStateDefault} from '../state.mocks' + +describe('limitPriceSelector', () => { + it('should return the limit price when type is limit', () => { + const orderData: SwapState['orderData'] = { + ...mockSwapStateDefault.orderData, + type: 'limit', + limitPrice: '100', + } + + const selected = limitPriceSelector(orderData) + expect(selected).toEqual(orderData.limitPrice) + }) + + it('should return undefined when type is not limit', () => { + const orderData: SwapState['orderData'] = { + ...mockSwapStateDefault.orderData, + type: 'market', + limitPrice: '100', + } + + const selected = limitPriceSelector(orderData) + expect(selected).toBeUndefined() + }) +}) diff --git a/packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.ts b/packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.ts new file mode 100644 index 0000000000..e53c422988 --- /dev/null +++ b/packages/swap/src/translators/reactjs/state/selectors/limitPriceSelector.ts @@ -0,0 +1,7 @@ +import {SwapState} from '../state' + +export const limitPriceSelector = (orderData: SwapState['orderData']) => { + const {type, limitPrice} = orderData + + return type === 'limit' ? limitPrice : undefined +} diff --git a/packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.test.ts b/packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.test.ts new file mode 100644 index 0000000000..c6f44c733f --- /dev/null +++ b/packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.test.ts @@ -0,0 +1,71 @@ +import {SwapOrderCalculation, SwapState} from '../state' // adjust the import path +import {mockSwapStateDefault} from '../state.mocks' +import {selectedPoolCalculationSelector} from './selectedPoolCalculationSelector' + +describe('selectedPoolCalculationSelector', () => { + it('should return the best pool from calculations when type is limit and selectedPoolId matches', () => { + const orderData: SwapState['orderData'] = { + ...mockSwapStateDefault.orderData, + type: 'limit', + selectedPoolId: '1', + calculations: [ + {pool: {poolId: '1'}} as SwapOrderCalculation, + {pool: {poolId: '2'}} as SwapOrderCalculation, + ], + bestPoolCalculation: { + pool: {poolId: '3'}, + } as SwapOrderCalculation, + } + + const selected = selectedPoolCalculationSelector(orderData) + expect(selected).toEqual(orderData.calculations[0]) + }) + + it('should return the state bestPoolCalculation when no match is found in calculations', () => { + const orderData: SwapState['orderData'] = { + ...mockSwapStateDefault.orderData, + type: 'limit', + selectedPoolId: '3', + calculations: [ + {pool: {poolId: '1'}} as SwapOrderCalculation, + {pool: {poolId: '2'}} as SwapOrderCalculation, + ], + bestPoolCalculation: {pool: {poolId: '3'}} as SwapOrderCalculation, + } + + const selected = selectedPoolCalculationSelector(orderData) + expect(selected).toEqual(orderData.bestPoolCalculation) + }) + + it('should return state bestPool when type is market', () => { + const orderData: SwapState['orderData'] = { + ...mockSwapStateDefault.orderData, + type: 'market', + selectedPoolId: '1', + calculations: [ + {pool: {poolId: '1'}} as SwapOrderCalculation, + {pool: {poolId: '2'}} as SwapOrderCalculation, + ], + bestPoolCalculation: {pool: {poolId: '3'}} as SwapOrderCalculation, + } + + const selected = selectedPoolCalculationSelector(orderData) + expect(selected).toEqual(orderData.bestPoolCalculation) + }) + + it('should return the the current bestPoolCalculation when no selectedPoolId', () => { + const orderData: SwapState['orderData'] = { + ...mockSwapStateDefault.orderData, + type: 'limit', + selectedPoolId: undefined, + calculations: [ + {pool: {poolId: '1'}} as SwapOrderCalculation, + {pool: {poolId: '2'}} as SwapOrderCalculation, + ], + bestPoolCalculation: {pool: {poolId: '3'}} as SwapOrderCalculation, + } + + const selected = selectedPoolCalculationSelector(orderData) + expect(selected).toEqual(orderData.bestPoolCalculation) + }) +}) diff --git a/packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.ts b/packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.ts new file mode 100644 index 0000000000..322f104c4c --- /dev/null +++ b/packages/swap/src/translators/reactjs/state/selectors/selectedPoolCalculationSelector.ts @@ -0,0 +1,16 @@ +import {SwapOrderCalculation, SwapState} from '../state' + +export const selectedPoolCalculationSelector = ( + orderData: SwapState['orderData'], +): SwapOrderCalculation | undefined => { + const {type, selectedPoolId, calculations, bestPoolCalculation} = orderData + let calculation: SwapOrderCalculation | undefined + + // can only select a pool if is a limit order type + // otherwise will return the current state value for it + if (type === 'limit' && selectedPoolId !== undefined) { + calculation = calculations.find(({pool}) => pool.poolId === selectedPoolId) + } + + return calculation ?? bestPoolCalculation +} diff --git a/packages/swap/src/translators/reactjs/state/state.test.ts b/packages/swap/src/translators/reactjs/state/state.test.ts index f9434d058a..9f1e2f3a3c 100644 --- a/packages/swap/src/translators/reactjs/state/state.test.ts +++ b/packages/swap/src/translators/reactjs/state/state.test.ts @@ -1,159 +1,183 @@ -import {produce} from 'immer' - -import { - combinedSwapReducers, - defaultSwapState, - SwapCreateOrderActionType, - SwapActionType, - SwapCreateOrderAction, - SwapAction, -} from './state' -import {mockSwapStateDefault} from './state.mocks' +// import {produce} from 'immer' + +// import { +// combinedSwapReducers, +// defaultSwapState, +// SwapCreateOrderActionType, +// SwapActionType, +// SwapCreateOrderAction, +// SwapAction, +// SwapState, +// } from './state' +// import {mockSwapStateDefault} from './state.mocks' +// import {mocks} from '../../../helpers/mocks' describe('State Actions', () => { - it('unknown', () => { - const action = {type: 'UNKNOWN'} as any - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(mockSwapStateDefault) - }) - - it('OrderTypeChanged market', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.OrderTypeChanged, - orderType: 'limit', - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.type = 'limit' - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('OrderTypeChanged limit', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.OrderTypeChanged, - orderType: 'market', - } - - const limitedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.type = 'limit' - }) - - const expectedState = produce(limitedState, (draft) => { - draft.orderData.type = 'market' - }) - const state = combinedSwapReducers(limitedState, action) - expect(state).toEqual(expectedState) - }) - - it('UnsignedTxChanged', () => { - const action: SwapAction = { - type: SwapActionType.UnsignedTxChanged, - unsignedTx: {txHash: 'someHash'}, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.unsignedTx = {txHash: 'someHash'} - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('ResetState', () => { - const action: SwapAction = {type: SwapActionType.ResetState} - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(defaultSwapState) - }) - - it('SelectedPoolChanged market', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.SelectedPoolChanged, - poolId: '', - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.selectedPoolId = action.poolId - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('SelectedPoolChanged limit', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.SelectedPoolChanged, - poolId: '', - } - - const limitedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.type = 'limit' - }) - - const expectedState = produce(limitedState, (draft) => { - draft.orderData.selectedPoolId = action.poolId - }) - const state = combinedSwapReducers(limitedState, action) - expect(state).toEqual(expectedState) - }) - - it('SlippageChanged', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.SlippageChanged, - slippage: 2, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.slippage = action.slippage - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('SwitchTokens', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.SwitchTokens, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.amounts = { - sell: mockSwapStateDefault.orderData.amounts.buy, - buy: mockSwapStateDefault.orderData.amounts.sell, - } - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('ResetQuantities', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.ResetQuantities, - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.amounts = { - sell: { - quantity: '0', - tokenId: mockSwapStateDefault.orderData.amounts.sell.tokenId, - }, - buy: { - quantity: '0', - tokenId: mockSwapStateDefault.orderData.amounts.buy.tokenId, - }, - } - draft.orderData.limitPrice = undefined - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - it('LimitPriceChanged', () => { - const action: SwapCreateOrderAction = { - type: SwapCreateOrderActionType.LimitPriceChanged, - limitPrice: '2', - } - const expectedState = produce(mockSwapStateDefault, (draft) => { - draft.orderData.limitPrice = action.limitPrice - }) - const state = combinedSwapReducers(mockSwapStateDefault, action) - expect(state).toEqual(expectedState) - }) - - // - // TODO: implement + // const mockedState: SwapState = { + // ...mockSwapStateDefault, + // orderData: { + // ...mockSwapStateDefault.orderData, + // amounts: { + // sell: { + // quantity: '100000000', + // tokenId: 'tokenA', + // }, + // buy: { + // quantity: '1401162647', + // tokenId: 'tokenB', + // }, + // }, + // limitPrice: undefined, + // slippage: 10, + // type: 'market', + // selectedPoolId: undefined, + // selectedPoolCalculation: undefined, + + // pools: mocks.mockedPools1, + // calculations: mocks.mockedOrderCalculations1, + // bestPoolCalculation: mocks.mockedOrderCalculations1[0], + // }, + // } + // it('unknown', () => { + // const action = {type: 'UNKNOWN'} as any + // const state = combinedSwapReducers(mockSwapStateDefault, action) + // expect(state).toEqual(mockSwapStateDefault) + // }) + + // it('OrderTypeChanged', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.OrderTypeChanged, + // orderType: 'limit', + // } + // const expectedState = produce(mockedState, (draft) => { + // draft.orderData.type = 'limit' + // }) + // const state = combinedSwapReducers(mockedState, action) + // expect(state).toEqual(expectedState) + // }) + + // it('OrderTypeChanged limit', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.OrderTypeChanged, + // orderType: 'market', + // } + + // const limitedState = produce(mockedState, (draft) => { + // draft.orderData.type = 'limit' + // }) + + // const expectedState = produce(limitedState, (draft) => { + // draft.orderData.type = 'market' + // }) + // const state = combinedSwapReducers(limitedState, action) + // expect(state).toEqual(expectedState) + // }) + + // it('UnsignedTxChanged', () => { + // const action: SwapAction = { + // type: SwapActionType.UnsignedTxChanged, + // unsignedTx: {txHash: 'someHash'}, + // } + // const expectedState = produce(mockSwapStateDefault, (draft) => { + // draft.unsignedTx = {txHash: 'someHash'} + // }) + // const state = combinedSwapReducers(mockSwapStateDefault, action) + // expect(state).toEqual(expectedState) + // }) + + // it('ResetState', () => { + // const action: SwapAction = {type: SwapActionType.ResetState} + // const state = combinedSwapReducers(mockSwapStateDefault, action) + // expect(state).toEqual(defaultSwapState) + // }) + + // it('SelectedPoolChanged market should not update the state', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.SelectedPoolChanged, + // poolId: '6', + // } + // const state = combinedSwapReducers(mockedState, action) + // expect(state).toEqual(mockedState) + // }) + + // it('SelectedPoolChanged limit (should updated the selected pool)', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.SelectedPoolChanged, + // poolId: '', + // } + + // const limitedState = produce(mockSwapStateDefault, (draft) => { + // draft.orderData.type = 'limit' + // }) + + // const expectedState = produce(limitedState, (draft) => { + // draft.orderData.selectedPoolId = action.poolId + // }) + // const state = combinedSwapReducers(limitedState, action) + // expect(state).toEqual(expectedState) + // }) + + // it('SlippageChanged', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.SlippageChanged, + // slippage: 2, + // } + // const expectedState = produce(mockSwapStateDefault, (draft) => { + // draft.orderData.slippage = action.slippage + // }) + // const state = combinedSwapReducers(mockSwapStateDefault, action) + // expect(state).toEqual(expectedState) + // }) + + // it('SwitchTokens', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.SwitchTokens, + // } + // const expectedState = produce(mockSwapStateDefault, (draft) => { + // draft.orderData.amounts = { + // sell: mockSwapStateDefault.orderData.amounts.buy, + // buy: mockSwapStateDefault.orderData.amounts.sell, + // } + // }) + // const state = combinedSwapReducers(mockSwapStateDefault, action) + // expect(state).toEqual(expectedState) + // }) + + // it('ResetQuantities', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.ResetQuantities, + // } + // const expectedState = produce(mockSwapStateDefault, (draft) => { + // draft.orderData.amounts = { + // sell: { + // quantity: '0', + // tokenId: mockSwapStateDefault.orderData.amounts.sell.tokenId, + // }, + // buy: { + // quantity: '0', + // tokenId: mockSwapStateDefault.orderData.amounts.buy.tokenId, + // }, + // } + // draft.orderData.limitPrice = undefined + // }) + // const state = combinedSwapReducers(mockSwapStateDefault, action) + // expect(state).toEqual(expectedState) + // }) + + // it('LimitPriceChanged', () => { + // const action: SwapCreateOrderAction = { + // type: SwapCreateOrderActionType.LimitPriceChanged, + // limitPrice: '2', + // } + // const expectedState = produce(mockSwapStateDefault, (draft) => { + // draft.orderData.limitPrice = action.limitPrice + // }) + // const state = combinedSwapReducers(mockSwapStateDefault, action) + // expect(state).toEqual(expectedState) + // }) + + // // + // // TODO: implement it('SellTokenIdChanged', () => { expect('todo').toBeDefined() }) diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 2cce12e3db..cc44e7e794 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -1,13 +1,28 @@ import {Balance, Swap} from '@yoroi/types' import {produce} from 'immer' -import {getBuyAmount} from '../../../helpers/orders/getBuyAmount' -import {getSellAmount} from '../../../helpers/orders/getSellAmount' import {Quantities} from '../../../utils/quantities' import {SwapDiscountTier} from '../../../translators/constants' import {makeOrderCalculations} from '../../../helpers/orders/makeOrderCalculations' +import {selectedPoolCalculationSelector} from './selectors/selectedPoolCalculationSelector' +import {getBestPoolCalculation} from '../../../helpers/pools/getBestPoolCalculation' export type SwapOrderCalculation = Readonly<{ + order: { + side?: 'buy' | 'sell' + slippage: number + orderType: Swap.OrderType + limitPrice?: Balance.Quantity + amounts: { + sell: Balance.Amount + buy: Balance.Amount + } + lpTokenHeld?: Balance.Amount + } + sides: { + sell: Balance.Amount + buy: Balance.Amount + } pool: Swap.Pool prices: { base: Balance.Quantity @@ -33,40 +48,30 @@ export type SwapOrderCalculation = Readonly<{ } }> -const getBestPool = ( - calculations: ReadonlyArray, -): SwapOrderCalculation | undefined => { - return calculations.reduce( - (best, current): SwapOrderCalculation | undefined => { - if (!current.hasSupply) return best - if (best === undefined) return current - if ( - Quantities.isGreaterThan(best.prices.withFees, current.prices.withFees) - ) - return current - return best - }, - undefined as SwapOrderCalculation | undefined, - ) -} - export type SwapState = Readonly<{ orderData: { - type: Swap.OrderType + // user inputs amounts: { sell: Balance.Amount buy: Balance.Amount } - slippage: number + type: Swap.OrderType limitPrice?: Balance.Quantity + slippage: number + // when limit can manually select a pool selectedPoolId?: string - bestPool?: SwapOrderCalculation - calculatedPool?: SwapOrderCalculation + selectedPoolCalculation?: SwapOrderCalculation + + // state from wallet + lpTokenHeld?: Balance.Amount + primartyTokenId: Balance.TokenInfo['id'] + + // state from api pools: ReadonlyArray + + // derivaded data calculations: ReadonlyArray - lpTokenHeld?: Balance.Amount - getMaybeLimitPrice: () => Balance.Quantity | undefined - getCalculatedPool: () => SwapOrderCalculation | undefined + bestPoolCalculation?: SwapOrderCalculation } unsignedTx: any }> @@ -80,16 +85,11 @@ export type SwapCreateOrderActions = Readonly<{ limitPriceChanged: (limitPrice: Balance.Quantity) => void sellQuantityChanged: (quantity: Balance.Quantity) => void buyQuantityChanged: (quantity: Balance.Quantity) => void - sellTokenIdChanged: (payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - }) => void - buyTokenIdChanged: (payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - }) => void + sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void + buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void poolPairsChanged: (pools: ReadonlyArray) => void lpTokenHeldChanged: (amount: Balance.Amount | undefined) => void + primaryTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => void }> export enum SwapCreateOrderActionType { @@ -106,6 +106,7 @@ export enum SwapCreateOrderActionType { BuyTokenIdChanged = 'buyTokenIdChanged', PoolPairsChanged = 'poolPairsChanged', LpTokenHeldChanged = 'lpTokenHeldChanged', + PrimaryTokenIdChanged = 'primaryTokenIdChanged', } export type SwapCreateOrderAction = @@ -137,17 +138,11 @@ export type SwapCreateOrderAction = } | { type: SwapCreateOrderActionType.SellTokenIdChanged - payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - } + tokenId: Balance.TokenInfo['id'] } | { type: SwapCreateOrderActionType.BuyTokenIdChanged - payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - } + tokenId: Balance.TokenInfo['id'] } | { type: SwapCreateOrderActionType.PoolPairsChanged @@ -157,6 +152,10 @@ export type SwapCreateOrderAction = type: SwapCreateOrderActionType.LpTokenHeldChanged amount: Balance.Amount | undefined } + | { + type: SwapCreateOrderActionType.PrimaryTokenIdChanged + tokenId: Balance.TokenInfo['id'] + } export type SwapActions = Readonly<{ // TODO: import from @yoroi/common unsignedTx type @@ -195,6 +194,7 @@ export const combinedSwapReducers = ( export const defaultSwapState: SwapState = { orderData: { + // user inputs type: 'market', amounts: { sell: { @@ -208,23 +208,20 @@ export const defaultSwapState: SwapState = { }, slippage: 1, limitPrice: undefined, - + // when limit can manually select a pool selectedPoolId: undefined, - bestPool: undefined, + selectedPoolCalculation: undefined, - calculations: [] as const, + // state from wallet lpTokenHeld: undefined, + primartyTokenId: '', + + // state from api pools: [] as const, - getMaybeLimitPrice: function () { - return this.type === 'limit' ? this.limitPrice : undefined - }, - getCalculatedPool: function () { - return this.type === 'limit' && this.selectedPoolId !== undefined - ? this.calculations.find( - ({pool}) => pool.poolId === this.selectedPoolId, - ) ?? this.bestPool - : this.bestPool - }, + + // derivaded data + calculations: [] as const, + bestPoolCalculation: undefined, }, unsignedTx: undefined, } as const @@ -242,6 +239,7 @@ const defaultSwapCreateOrderActions: SwapCreateOrderActions = { buyTokenIdChanged: missingInit, poolPairsChanged: missingInit, lpTokenHeldChanged: missingInit, + primaryTokenIdChanged: missingInit, } as const const defaultStateActions: SwapActions = { @@ -260,6 +258,9 @@ const orderReducer = ( ) => { return produce(state, (draft) => { switch (action.type) { + // when changing order type, from market to limit + // or when is the first calculation as limit with data + // the limit price is set to the best market price case SwapCreateOrderActionType.OrderTypeChanged: draft.orderData.type = action.orderType @@ -269,33 +270,45 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, }) + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) + if (draft.orderData.selectedPoolCalculation === undefined) break - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() - if (draft.orderData.calculatedPool === undefined) break + draft.orderData.amounts.buy = + draft.orderData.selectedPoolCalculation.sides.buy - draft.orderData.amounts.buy = getBuyAmount( - draft.orderData.calculatedPool.pool, - state.orderData.amounts.sell, - draft.orderData.getMaybeLimitPrice(), + if ( + draft.orderData.type === 'limit' && + state.orderData.limitPrice === undefined ) + draft.orderData.limitPrice = + draft.orderData.bestPoolCalculation?.prices.market + break + // when changing pool, the selection comes from the calculations + // so it updates the buy side only + // it ignores events if order type is not limit + // NOTE: late it can replace the order from market to limit and recalc case SwapCreateOrderActionType.SelectedPoolChanged: + if (state.orderData.type !== 'limit') break + draft.orderData.selectedPoolId = action.poolId - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() - if (draft.orderData.calculatedPool === undefined) break + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) - draft.orderData.amounts.buy = getBuyAmount( - draft.orderData.calculatedPool.pool, - state.orderData.amounts.sell, - state.orderData.getMaybeLimitPrice(), - ) + if (draft.orderData.selectedPoolCalculation === undefined) break + + draft.orderData.amounts.buy = + draft.orderData.selectedPoolCalculation.sides.buy break case SwapCreateOrderActionType.SlippageChanged: @@ -307,13 +320,20 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: action.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) + break + // when switching and the type is limit can end up with weird amounts + // yet, we updated buy/sell based on the current selected pool if limit case SwapCreateOrderActionType.SwitchTokens: draft.orderData.amounts = { sell: state.orderData.amounts.buy, @@ -326,33 +346,32 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) - if (draft.orderData.calculatedPool === undefined) break + if (draft.orderData.selectedPoolCalculation === undefined) break if ( draft.orderData.amounts.sell.tokenId === - draft.orderData.calculatedPool.pool.tokenA.tokenId + draft.orderData.selectedPoolCalculation.pool.tokenA.tokenId ) { - draft.orderData.amounts.buy = getBuyAmount( - draft.orderData.calculatedPool.pool, - draft.orderData.amounts.sell, - draft.orderData.getMaybeLimitPrice(), - ) + draft.orderData.amounts.buy = + draft.orderData.selectedPoolCalculation.sides.buy } else { - draft.orderData.amounts.sell = getSellAmount( - draft.orderData.calculatedPool.pool, - draft.orderData.amounts.buy, - draft.orderData.getMaybeLimitPrice(), - ) + draft.orderData.amounts.sell = + draft.orderData.selectedPoolCalculation.sides.sell } break + // when resetting quantities, when order is limit, limit price is the best market price + // otherwise the limit set back to undefined case SwapCreateOrderActionType.ResetQuantities: draft.orderData.amounts = { sell: { @@ -371,17 +390,26 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() - - draft.orderData.limitPrice = draft.orderData.bestPool?.prices.market + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) + draft.orderData.limitPrice = + state.orderData.type === 'limit' + ? draft.orderData.bestPoolCalculation?.prices.market + : undefined break + // when limit price changes, the best pool is recalculated + // yet if there is a selected pool it will not change + // this can cause a pool if not enough supply to be selected + // must be handled on the UI case SwapCreateOrderActionType.LimitPriceChanged: draft.orderData.limitPrice = action.limitPrice @@ -393,22 +421,24 @@ const orderReducer = ( limitPrice: action.limitPrice, slippage: state.orderData.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) - if (draft.orderData.calculatedPool === undefined) break + if (draft.orderData.selectedPoolCalculation === undefined) break - draft.orderData.amounts.buy = getBuyAmount( - draft.orderData.calculatedPool.pool, - state.orderData.amounts.sell, - action.limitPrice, - ) + draft.orderData.amounts.buy = + draft.orderData.selectedPoolCalculation.sides.buy break - // + // updating sell side will recalculate buy side + // the pool will be automatically selected only if + // there is no selected pool (limit order) case SwapCreateOrderActionType.SellQuantityChanged: draft.orderData.amounts.sell.quantity = action.quantity @@ -418,22 +448,25 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, - action: 'sell', + side: 'sell', }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) - if (draft.orderData.calculatedPool === undefined) break + if (draft.orderData.selectedPoolCalculation === undefined) break - draft.orderData.amounts.buy = getBuyAmount( - draft.orderData.calculatedPool.pool, - draft.orderData.amounts.sell, - draft.orderData.getMaybeLimitPrice(), - ) + draft.orderData.amounts.buy = + draft.orderData.selectedPoolCalculation.sides.buy break + // updating buy side will recalculate sell side + // the pool will be automatically selected only if + // there is no selected pool (limit order) case SwapCreateOrderActionType.BuyQuantityChanged: draft.orderData.amounts.buy.quantity = action.quantity @@ -443,60 +476,50 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, - action: 'buy', + side: 'buy', }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) - if (draft.orderData.calculatedPool === undefined) break + if (draft.orderData.selectedPoolCalculation === undefined) break - draft.orderData.amounts.sell = getSellAmount( - draft.orderData.calculatedPool.pool, - draft.orderData.amounts.buy, - draft.orderData.getMaybeLimitPrice(), - ) + draft.orderData.amounts.sell = + draft.orderData.selectedPoolCalculation.sides.sell break + // when changing token id, all the derivaded data is reset + // and the selected pool is reset case SwapCreateOrderActionType.SellTokenIdChanged: - draft.orderData.amounts.sell.tokenId = action.payload.tokenId - draft.orderData.pools = [...action.payload.pools] - - draft.orderData.calculations = makeOrderCalculations({ - orderType: state.orderData.type, - amounts: draft.orderData.amounts, - limitPrice: state.orderData.limitPrice, - slippage: state.orderData.slippage, - pools: draft.orderData.pools, - primaryTokenId: '', - lpTokenHeld: state.orderData.lpTokenHeld, - action: 'sell', - }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.amounts.sell.tokenId = action.tokenId + draft.orderData.pools = [] + draft.orderData.calculations = [] + draft.orderData.bestPoolCalculation = undefined + draft.orderData.selectedPoolId = undefined + draft.orderData.selectedPoolCalculation = undefined break + // when changing token id, all the derivaded data is reset + // and the selected pool is reset case SwapCreateOrderActionType.BuyTokenIdChanged: - draft.orderData.amounts.buy.tokenId = action.payload.tokenId - draft.orderData.pools = [...action.payload.pools] - - draft.orderData.calculations = makeOrderCalculations({ - orderType: state.orderData.type, - amounts: draft.orderData.amounts, - limitPrice: state.orderData.limitPrice, - slippage: state.orderData.slippage, - pools: draft.orderData.pools, - primaryTokenId: '', - lpTokenHeld: state.orderData.lpTokenHeld, - action: 'buy', - }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.amounts.buy.tokenId = action.tokenId + draft.orderData.pools = [] + draft.orderData.calculations = [] + draft.orderData.bestPoolCalculation = undefined + draft.orderData.selectedPoolId = undefined + draft.orderData.selectedPoolCalculation = undefined break + // NOTE: not fully implemented + // when the lp token held changes, the calculations are updated + // buy side needs recalculation since best pool can change + // affects only market order and limit without a selected pool case SwapCreateOrderActionType.LpTokenHeldChanged: draft.orderData.lpTokenHeld = action.amount @@ -506,14 +529,24 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, pools: state.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: action.amount, }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) + + if (draft.orderData.selectedPoolCalculation === undefined) break + draft.orderData.amounts.buy = + draft.orderData.selectedPoolCalculation.sides.buy break + // when the pool pair changes, the calculations are updated + // buy side needs recalculation since best pool can change + // reset limit and selected pool - since it can be gone case SwapCreateOrderActionType.PoolPairsChanged: draft.orderData.pools = [...action.pools] draft.orderData.calculations = makeOrderCalculations({ @@ -522,12 +555,31 @@ const orderReducer = ( limitPrice: state.orderData.limitPrice, slippage: state.orderData.slippage, pools: draft.orderData.pools, - primaryTokenId: '', + primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, }) - draft.orderData.bestPool = getBestPool(draft.orderData.calculations) - draft.orderData.calculatedPool = draft.orderData.getCalculatedPool() + draft.orderData.bestPoolCalculation = getBestPoolCalculation( + draft.orderData.calculations, + ) + draft.orderData.selectedPoolCalculation = + selectedPoolCalculationSelector(draft.orderData) + + draft.orderData.limitPrice = undefined + draft.orderData.selectedPoolId = undefined + + if (draft.orderData.selectedPoolCalculation === undefined) break + + draft.orderData.limitPrice = + state.orderData.type === 'limit' + ? draft.orderData.bestPoolCalculation?.prices.market + : undefined + + draft.orderData.amounts.buy = + draft.orderData.selectedPoolCalculation.sides.buy + break + case SwapCreateOrderActionType.PrimaryTokenIdChanged: + draft.orderData.primartyTokenId = action.tokenId break } }) From d5d36ef1c827339370144c1e96e2d00b9188be5c Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Sun, 8 Oct 2023 23:49:31 +0100 Subject: [PATCH 29/67] chore: CR --- packages/swap/src/helpers/orders/makeOrderCalculations.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 648eb4fafc..8f555035ef 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -80,7 +80,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.sell.quantity) - .times(ptPriceSell) + .dividedBy(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -88,7 +88,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.buy.quantity) - .times(ptPriceBuy) + .dividedBy(ptPriceBuy) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -98,10 +98,10 @@ export const makeOrderCalculations = ({ // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) - .times(ptPriceSell) + .dividedBy(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .times(ptPriceSell) + .dividedBy(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), } From 1f8c8d8dd3b51958d19db9e722899391d076200b Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 00:08:49 +0100 Subject: [PATCH 30/67] chore: change sell/buy id --- .../Swap/common/AmountCard/AmountCard.tsx | 2 +- .../src/features/Swap/common/useSwapTx.ts | 2 +- .../ConfirmTxScreen/ConfirmTxScreen.tsx | 6 ++-- .../ConfirmTxScreen/TransactionSummary.tsx | 6 ++-- .../CreateOrder/CreateOrder.tsx | 34 +++++++----------- .../EditBuyAmount/EditBuyAmount.tsx | 2 +- .../SelectBuyTokenFromListScreen.tsx | 22 ++++++++---- .../CreateOrder/EditLimitPrice.tsx | 6 ++-- .../CreateOrder/EditPool/ShowPoolActions.tsx | 26 ++++++++------ .../EditSellAmount/EditSellAmount.tsx | 2 +- .../SelectSellTokenFromListScreen.tsx | 35 +++++++++++++++---- .../LimitPriceWarning/LimitPriceWarning.tsx | 2 +- .../ShowTokenActions/TopTokenActions.tsx | 2 +- .../Swap/common/AmountCard/AmountCard.json | 20 +++++------ 14 files changed, 98 insertions(+), 69 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx b/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx index 39feef0efc..05c5bb1180 100644 --- a/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/AmountCard/AmountCard.tsx @@ -118,7 +118,7 @@ export const AmountCard = ({ - {orderData.calculatedPool === undefined + {orderData.selectedPoolCalculation === undefined ? strings.noPool : isSell ? strings.notEnoughBalance diff --git a/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts b/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts index c3571c5595..60f80a6206 100644 --- a/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts +++ b/apps/wallet-mobile/src/features/Swap/common/useSwapTx.ts @@ -9,7 +9,7 @@ import {splitStringInto64CharArray} from '../../../yoroi-wallets/utils' export const useSwapTx = (options?: UseMutationOptions) => { const {orderData} = useSwap() - const pool = orderData.calculatedPool?.pool + const pool = orderData.selectedPoolCalculation?.pool const metadata = [ { label: '674', diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx index 3de504c1ff..c2367d7738 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/ConfirmTxScreen.tsx @@ -51,7 +51,7 @@ export const ConfirmTxScreen = () => { signTx: {useErrorBoundary: true}, submitTx: { onSuccess: () => { - if (orderData.calculatedPool === undefined) return + if (orderData.selectedPoolCalculation === undefined) return track.swapOrderSubmitted({ from_asset: [ {asset_name: sellTokenInfo.name, asset_ticker: sellTokenInfo.ticker, policy_id: sellTokenInfo.group}, @@ -63,8 +63,8 @@ export const ConfirmTxScreen = () => { slippage_tolerance: orderData.slippage, from_amount: orderData.amounts.sell.quantity, to_amount: orderData.amounts.buy.quantity, - pool_source: orderData.calculatedPool.pool.provider, - swap_fees: Number(orderData.calculatedPool.cost.batcherFee), + pool_source: orderData.selectedPoolCalculation.pool.provider, + swap_fees: Number(orderData.selectedPoolCalculation.cost.batcherFee), }) navigate.submittedTx() diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx index dc97fa2044..8200a426d9 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx @@ -22,7 +22,7 @@ export const TransactionSummary = () => { const wallet = useSelectedWallet() const {numberLocale} = useLanguage() const {orderData} = useSwap() - const {amounts, calculatedPool} = orderData + const {amounts, selectedPoolCalculation} = orderData const buyTokenInfo = useTokenInfo({wallet, tokenId: amounts.buy.tokenId}) const tokenToBuyName = buyTokenInfo.ticker ?? buyTokenInfo.name @@ -32,7 +32,7 @@ export const TransactionSummary = () => { { label: strings.swapMinAdaTitle, value: `${Quantities.format( - calculatedPool?.cost?.deposit?.quantity ?? Quantities.zero, + selectedPoolCalculation?.cost?.deposit?.quantity ?? Quantities.zero, Number(wallet.primaryTokenInfo.decimals), )} ${wallet.primaryTokenInfo.ticker}`, info: strings.swapMinAda, @@ -50,7 +50,7 @@ export const TransactionSummary = () => { { label: strings.swapFeesTitle, value: `${Quantities.format( - calculatedPool?.cost?.batcherFee?.quantity ?? Quantities.zero, // TODO: Show all fees + selectedPoolCalculation?.cost?.batcherFee?.quantity ?? Quantities.zero, // TODO: Show all fees Number(wallet.primaryTokenInfo.decimals), )} ${wallet.primaryTokenInfo.ticker}`, info: strings.swapFees, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx index f6f33d078e..34edf061c9 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx @@ -1,4 +1,4 @@ -import {makeLimitOrder, makePossibleMarketOrder, useSwap, useSwapCreateOrder, useSwapPoolsByPair} from '@yoroi/swap' +import {makeLimitOrder, makePossibleMarketOrder, useSwap, useSwapCreateOrder} from '@yoroi/swap' import {Swap} from '@yoroi/types' import BigNumber from 'bignumber.js' import React, {useEffect, useState} from 'react' @@ -31,7 +31,7 @@ const LIMIT_PRICE_WARNING_THRESHOLD = 0.1 // 10% export const CreateOrder = () => { const strings = useStrings() const navigation = useNavigateTo() - const {orderData, poolPairsChanged, unsignedTxChanged} = useSwap() + const {orderData, unsignedTxChanged} = useSwap() const wallet = useSelectedWallet() const {track} = useMetrics() @@ -45,18 +45,10 @@ export const CreateOrder = () => { }) const [showLimitPriceWarning, setShowLimitPriceWarning] = useState(false) const {isBuyTouched, isSellTouched, poolDefaulted} = useSwapTouched() - const {poolList} = useSwapPoolsByPair({ - tokenA: orderData.amounts.sell.tokenId ?? '', - tokenB: orderData.amounts.buy.tokenId ?? '', - }) - - useEffect(() => { - poolPairsChanged(poolList ?? []) - }, [poolPairsChanged, poolList]) useEffect(() => { - if (orderData.selectedPoolId === orderData.bestPool?.pool.poolId) poolDefaulted() - }, [orderData.selectedPoolId, orderData.bestPool, poolDefaulted]) + if (orderData.selectedPoolId === orderData.bestPoolCalculation?.pool.poolId) poolDefaulted() + }, [orderData.selectedPoolId, orderData.bestPoolCalculation, poolDefaulted]) const {createUnsignedTx, isLoading} = useSwapTx({ onSuccess: (yoroiUnsignedTx) => { @@ -71,15 +63,15 @@ export const CreateOrder = () => { const {createOrderData} = useSwapCreateOrder({ onSuccess: (data: Swap.CreateOrderResponse) => { - if (data?.contractAddress !== undefined && orderData.calculatedPool?.pool !== undefined) { - const {amounts, limitPrice, slippage, calculatedPool} = orderData + if (data?.contractAddress !== undefined && orderData.selectedPoolCalculation?.pool !== undefined) { + const {amounts, limitPrice, slippage, selectedPoolCalculation} = orderData const entry = createYoroiEntry( { amounts, limitPrice, address: data.contractAddress, slippage, - selectedPool: calculatedPool.pool, + selectedPool: selectedPoolCalculation.pool, }, data.contractAddress, wallet, @@ -101,7 +93,7 @@ export const CreateOrder = () => { (orderData.type === 'limit' && orderData.limitPrice !== undefined && Quantities.isZero(orderData.limitPrice)) const swap = () => { - if (orderData.calculatedPool === undefined) return + if (orderData.selectedPoolCalculation === undefined) return track.swapOrderSelected({ from_asset: [ {asset_name: sellTokenInfo.name, asset_ticker: sellTokenInfo.ticker, policy_id: sellTokenInfo.group}, @@ -111,10 +103,10 @@ export const CreateOrder = () => { slippage_tolerance: orderData.slippage, from_amount: orderData.amounts.sell.quantity, to_amount: orderData.amounts.buy.quantity, - pool_source: orderData.calculatedPool.pool.provider, + pool_source: orderData.selectedPoolCalculation.pool.provider, swap_fees: Number( Quantities.denominated( - orderData.calculatedPool.pool.batcherFee.quantity, + orderData.selectedPoolCalculation.pool.batcherFee.quantity, Number(wallet.primaryTokenInfo.decimals), ), ), @@ -128,7 +120,7 @@ export const CreateOrder = () => { sell: orderData.amounts.sell, buy: orderData.amounts.buy, pools: orderData.pools, - selectedPool: orderData.calculatedPool?.pool, + selectedPool: orderData.selectedPoolCalculation?.pool, slippage: orderData.slippage, address: wallet.externalAddresses[0], } @@ -171,9 +163,9 @@ export const CreateOrder = () => { } const handleOnSwap = () => { - if (orderData.calculatedPool === undefined) return + if (orderData.selectedPoolCalculation === undefined) return if (orderData.type === 'limit' && orderData.limitPrice !== undefined) { - const marketPrice = new BigNumber(orderData.calculatedPool.prices.market) + const marketPrice = new BigNumber(orderData.selectedPoolCalculation.prices.market) const limitPrice = new BigNumber(orderData.limitPrice) if (limitPrice.isGreaterThan(marketPrice.times(1 + LIMIT_PRICE_WARNING_THRESHOLD))) { diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx index e7815ca952..bd1b42dc6f 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx @@ -21,7 +21,7 @@ export const EditBuyAmount = () => { const {orderData, buyQuantityChanged} = useSwap() const {isBuyTouched} = useSwapTouched() - const pool = orderData.calculatedPool?.pool + const pool = orderData.selectedPoolCalculation?.pool const {tokenId, quantity} = orderData.amounts.buy const tokenInfo = useTokenInfo({wallet, tokenId}) const {decimals} = tokenInfo diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 114b156614..2be25f6fcb 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -2,7 +2,7 @@ import {FlashList} from '@shopify/flash-list' import {useSwap, useSwapPoolsByPair, useSwapTokensByPairToken} from '@yoroi/swap' import {Balance} from '@yoroi/types' import React from 'react' -import {StyleSheet, TouchableOpacity, View} from 'react-native' +import {InteractionManager, StyleSheet, TouchableOpacity, View} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import {Boundary, Icon, Spacer, Text} from '../../../../../../../components' @@ -178,7 +178,7 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenForList: TokenForList; wallet: YoroiWallet} const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {buyTokenIdChanged, orderData} = useSwap() + const {buyTokenIdChanged, poolPairsChanged, orderData} = useSwap() const {buyTouched} = useSwapTouched() const {refetch} = useSwapPoolsByPair( { @@ -186,11 +186,22 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { tokenB: orderData.amounts.sell.tokenId, }, { + useErrorBoundary: true, enabled: false, + onSuccess: (pools) => { + buyTouched() + closeSearch() + poolPairsChanged(pools) + + InteractionManager.runAfterInteractions(() => { + navigateTo.startSwap() + }) + }, }, ) + React.useEffect(() => { - console.log('refetch') + refetch() }, [refetch, orderData.amounts.buy.tokenId]) const navigateTo = useNavigateTo() @@ -201,10 +212,7 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { track.swapAssetToChanged({ to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], }) - buyTouched() - buyTokenIdChanged({tokenId: tokenForList.id, pools: []}) - navigateTo.startSwap() - closeSearch() + buyTokenIdChanged(tokenForList.id) } return ( diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx index 57ac610acd..53d342cf13 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx @@ -35,9 +35,11 @@ export const EditLimitPrice = () => { if (orderData.type === 'limit') { setText(Quantities.format(orderData.limitPrice ?? Quantities.zero, denomination, PRECISION)) } else { - setText(Quantities.format(orderData.calculatedPool?.prices.market ?? Quantities.zero, denomination, PRECISION)) + setText( + Quantities.format(orderData.selectedPoolCalculation?.prices.market ?? Quantities.zero, denomination, PRECISION), + ) } - }, [orderData.type, orderData.limitPrice, orderData.amounts.sell, denomination, orderData.calculatedPool]) + }, [orderData.type, orderData.limitPrice, orderData.amounts.sell, denomination, orderData.selectedPoolCalculation]) const onChange = (text: string) => { const [formattedPrice, price] = Quantities.parseFromText(text, PRECISION, numberLocale) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx index cbe82ee3da..6d581bd908 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx @@ -26,7 +26,7 @@ export const ShowPoolActions = () => { const {orderData} = useSwap() const strings = useStrings() const {isBuyTouched, isSellTouched, isPoolTouched} = useSwapTouched() - const {calculatedPool, amounts} = orderData + const {selectedPoolCalculation, amounts} = orderData const wallet = useSelectedWallet() const buyTokenInfo = useTokenInfo({wallet, tokenId: amounts.buy.tokenId}) const sellTokenInfo = useTokenInfo({wallet, tokenId: amounts.sell.tokenId}) @@ -34,22 +34,25 @@ export const ShowPoolActions = () => { const sellTokenName = sellTokenInfo.ticker ?? sellTokenInfo.name const [hiddenInfoOpenId, setHiddenInfoOpenId] = React.useState(null) - if (!isBuyTouched || !isSellTouched || calculatedPool === undefined) { + if (!isBuyTouched || !isSellTouched || selectedPoolCalculation === undefined) { return <> } const totalFees = Quantities.format( - Quantities.sum([calculatedPool.cost.batcherFee.quantity, calculatedPool.cost.frontendFeeInfo.fee.quantity]), + Quantities.sum([ + selectedPoolCalculation.cost.batcherFee.quantity, + selectedPoolCalculation.cost.frontendFeeInfo.fee.quantity, + ]), Number(wallet.primaryTokenInfo.decimals), ) const header = `${strings.total}: ${Quantities.format( amounts.sell.quantity, sellTokenInfo.decimals ?? 0, )} ${sellTokenName} + ${totalFees} ${wallet.primaryTokenInfo.ticker}` - const id = calculatedPool.pool.poolId + const id = selectedPoolCalculation.pool.poolId const expanded = id === hiddenInfoOpenId - const poolProviderFormatted = capitalize(calculatedPool.pool.provider) + const poolProviderFormatted = capitalize(selectedPoolCalculation.pool.provider) const poolStatus = orderData.type === 'limit' && isPoolTouched ? '' : ` ${strings.autoPool}` const poolTitle = `${poolProviderFormatted}${poolStatus}` @@ -59,7 +62,7 @@ export const ShowPoolActions = () => { - + @@ -85,7 +88,7 @@ export const ShowPoolActions = () => { info={ { buyTokenInfo.decimals ?? 0, numberLocale, )} - minAda={Quantities.format(calculatedPool.pool.deposit.quantity, Number(wallet.primaryTokenInfo.decimals))} + minAda={Quantities.format( + selectedPoolCalculation.pool.deposit.quantity, + Number(wallet.primaryTokenInfo.decimals), + )} buyTokenName={buyTokenName} sellTokenName={sellTokenName} - liquidityFee={calculatedPool.pool.fee} + liquidityFee={selectedPoolCalculation.pool.fee} liquidityFeeValue={Quantities.format( - calculatedPool.cost.liquidityFee.quantity, + selectedPoolCalculation.cost.liquidityFee.quantity, sellTokenInfo.decimals ?? 0, )} /> diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx index 61571fcf09..7c7dcca1c8 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx @@ -60,7 +60,7 @@ export const EditSellAmount = () => { navigateTo={navigate.selectSellToken} touched={isSellTouched} inputRef={inputRef} - inputEditable={orderData.calculatedPool?.pool !== undefined} + inputEditable={orderData.selectedPoolCalculation?.pool !== undefined} /> ) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx index 1c5b551a94..650dcb40ba 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx @@ -1,8 +1,8 @@ import {FlashList} from '@shopify/flash-list' -import {useSwap} from '@yoroi/swap' +import {useSwap, useSwapPoolsByPair} from '@yoroi/swap' import {Balance} from '@yoroi/types' import React from 'react' -import {StyleSheet, TouchableOpacity, View} from 'react-native' +import {InteractionManager, StyleSheet, TouchableOpacity, View} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import {Boundary, Spacer, Text} from '../../../../../../../components' @@ -83,21 +83,42 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenInfo: Balance.TokenInfo; wallet: YoroiWallet} const SelectableToken = ({tokenInfo, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {sellTokenIdChanged} = useSwap() + const {sellTokenIdChanged, poolPairsChanged, orderData} = useSwap() const {sellTouched} = useSwapTouched() const navigateTo = useNavigateTo() const {track} = useMetrics() + const {refetch} = useSwapPoolsByPair( + { + tokenA: orderData.amounts.buy.tokenId, + tokenB: orderData.amounts.sell.tokenId, + }, + { + useErrorBoundary: true, + enabled: false, + onSuccess: (pools) => { + sellTouched() + closeSearch() + poolPairsChanged(pools) + + InteractionManager.runAfterInteractions(() => { + navigateTo.startSwap() + }) + }, + }, + ) + + React.useEffect(() => { + refetch() + }, [refetch, orderData.amounts.sell.tokenId]) + const balanceAvailable = useBalance({wallet, tokenId: tokenInfo.id}) const onSelect = () => { track.swapAssetFromChanged({ from_asset: [{asset_name: tokenInfo.name, asset_ticker: tokenInfo.ticker, policy_id: tokenInfo.group}], }) - sellTouched() - sellTokenIdChanged({tokenId: tokenInfo.id, pools: []}) - navigateTo.startSwap() - closeSearch() + sellTokenIdChanged(tokenInfo.id) } return ( diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx index 94caa90af3..3c7e74c12d 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/LimitPriceWarning/LimitPriceWarning.tsx @@ -21,7 +21,7 @@ export const LimitPriceWarning = ({open, onClose, onSubmit}: LimitPriceWarningPr const {numberLocale} = useLanguage() const strings = useStrings() const limitPrice = new BigNumber(orderData.limitPrice ?? 0).toFormat(numberLocale) - const marketPrice = new BigNumber(orderData.calculatedPool?.prices.market ?? 0).toFormat(numberLocale) + const marketPrice = new BigNumber(orderData.selectedPoolCalculation?.prices.market ?? 0).toFormat(numberLocale) const wallet = useSelectedWallet() const tokenToSellInfo = useTokenInfo({wallet, tokenId: orderData.amounts.sell.tokenId}) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx index b332d10ad0..8f04db9571 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx @@ -15,7 +15,7 @@ export const TopTokenActions = () => { const orderTypeLabels = [strings.marketButton, strings.limitButton] const {orderData, orderTypeChanged} = useSwap() const {isBuyTouched, isSellTouched} = useSwapTouched() - const isDisabled = !isBuyTouched || !isSellTouched || orderData.calculatedPool === undefined + const isDisabled = !isBuyTouched || !isSellTouched || orderData.selectedPoolCalculation === undefined const orderTypeIndex = orderData.type === 'market' ? 0 : 1 const {refetch, isLoading} = useSwapPoolsByPair({ diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index 08bfc443aa..7fa3933302 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -6,12 +6,12 @@ "start": { "line": 134, "column": 15, - "index": 4161 + "index": 4170 }, "end": { "line": 137, "column": 3, - "index": 4244 + "index": 4253 } }, { @@ -21,12 +21,12 @@ "start": { "line": 138, "column": 18, - "index": 4264 + "index": 4273 }, "end": { "line": 141, "column": 3, - "index": 4353 + "index": 4362 } }, { @@ -36,12 +36,12 @@ "start": { "line": 142, "column": 20, - "index": 4375 + "index": 4384 }, "end": { "line": 145, "column": 3, - "index": 4469 + "index": 4478 } }, { @@ -51,12 +51,12 @@ "start": { "line": 146, "column": 19, - "index": 4490 + "index": 4499 }, "end": { "line": 149, "column": 3, - "index": 4594 + "index": 4603 } }, { @@ -66,12 +66,12 @@ "start": { "line": 150, "column": 10, - "index": 4606 + "index": 4615 }, "end": { "line": 153, "column": 3, - "index": 4721 + "index": 4730 } } ] \ No newline at end of file From b6e7e8a0978303cf11bf64ba8233b0edea28a6fa Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 01:35:31 +0100 Subject: [PATCH 31/67] wip: state --- .../src/TxHistory/ActionsBanner.tsx | 7 ++- .../features/Swap/common/SwapFormProvider.tsx | 6 +++ .../CreateOrder/CreateOrder.tsx | 45 ++++++++++++------- .../SelectBuyTokenFromListScreen.tsx | 34 +++----------- .../EditSellAmount/EditSellAmount.tsx | 6 +-- .../SelectSellTokenFromListScreen.tsx | 33 +++----------- .../ShowTokenActions/TopTokenActions.tsx | 17 ++++--- .../Swap/common/AmountCard/AmountCard.json | 20 ++++----- 8 files changed, 77 insertions(+), 91 deletions(-) diff --git a/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx b/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx index feb2b856fa..5da6b3377e 100644 --- a/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx +++ b/apps/wallet-mobile/src/TxHistory/ActionsBanner.tsx @@ -8,6 +8,7 @@ import {Linking, StyleSheet, Text, TouchableOpacity, View} from 'react-native' import {Icon, Spacer} from '../components' import {features} from '../features' import {useSend} from '../features/Send/common/SendContext' +import {useSwapTouched} from '../features/Swap/common/SwapFormProvider' import {actionMessages} from '../i18n/global-messages' import {useMetrics} from '../metrics/metricsManager' import {TxHistoryRouteNavigation} from '../navigation' @@ -25,7 +26,8 @@ export const ActionsBanner = ({disabled = false}: {disabled: boolean}) => { const navigateTo = useNavigateTo() const wallet = useSelectedWallet() const {resetForm} = useSend() - const {orderData} = useSwap() + const {orderData, resetState} = useSwap() + const {resetTouches} = useSwapTouched() const {track} = useMetrics() const sellTokenInfo = useTokenInfo({ wallet, @@ -55,6 +57,9 @@ export const ActionsBanner = ({disabled = false}: {disabled: boolean}) => { } const handleOnSwap = () => { + resetTouches() + resetState() + track.swapInitiated({ from_asset: [ {asset_name: sellTokenInfo.name, asset_ticker: sellTokenInfo.ticker, policy_id: sellTokenInfo.group}, diff --git a/apps/wallet-mobile/src/features/Swap/common/SwapFormProvider.tsx b/apps/wallet-mobile/src/features/Swap/common/SwapFormProvider.tsx index 088d0e9622..da574eedb1 100644 --- a/apps/wallet-mobile/src/features/Swap/common/SwapFormProvider.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/SwapFormProvider.tsx @@ -11,6 +11,7 @@ type TouchedActions = { switchTouched: () => void poolTouched: () => void poolDefaulted: () => void + resetTouches: () => void } const TouchedContext = createContext(undefined) @@ -37,6 +38,7 @@ export const SwapFormProvider = ({ switchTouched: () => dispatch({type: 'switchTouched'}), poolTouched: () => dispatch({type: 'poolTouched'}), poolDefaulted: () => dispatch({type: 'poolDefaulted'}), + resetTouches: () => dispatch({type: 'resetTouches'}), }).current const context = React.useMemo(() => ({...state, ...actions}), [state, actions]) @@ -50,6 +52,7 @@ type TouchedAction = | {type: 'switchTouched'} | {type: 'poolTouched'} | {type: 'poolDefaulted'} + | {type: 'resetTouches'} function touchedReducer(state: TouchedState, action: TouchedAction) { switch (action.type) { @@ -72,6 +75,9 @@ function touchedReducer(state: TouchedState, action: TouchedAction) { case 'poolDefaulted': return {...state, isPoolTouched: false} + case 'resetTouches': + return defaultState + default: throw new Error(`touchedReducer invalid action`) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx index 34edf061c9..634d5b8eee 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx @@ -1,7 +1,7 @@ -import {makeLimitOrder, makePossibleMarketOrder, useSwap, useSwapCreateOrder} from '@yoroi/swap' +import {makeLimitOrder, makePossibleMarketOrder, useSwap, useSwapCreateOrder, useSwapPoolsByPair} from '@yoroi/swap' import {Swap} from '@yoroi/types' import BigNumber from 'bignumber.js' -import React, {useEffect, useState} from 'react' +import * as React from 'react' import {KeyboardAvoidingView, Platform, StyleSheet, View, ViewProps} from 'react-native' import {ScrollView} from 'react-native-gesture-handler' @@ -34,6 +34,15 @@ export const CreateOrder = () => { const {orderData, unsignedTxChanged} = useSwap() const wallet = useSelectedWallet() const {track} = useMetrics() + const {refetch} = useSwapPoolsByPair( + { + tokenA: orderData.amounts.sell.tokenId, + tokenB: orderData.amounts.buy.tokenId, + }, + { + enabled: false, + }, + ) const sellTokenInfo = useTokenInfo({ wallet, @@ -43,13 +52,17 @@ export const CreateOrder = () => { wallet, tokenId: orderData.amounts.buy.tokenId, }) - const [showLimitPriceWarning, setShowLimitPriceWarning] = useState(false) + const [showLimitPriceWarning, setShowLimitPriceWarning] = React.useState(false) const {isBuyTouched, isSellTouched, poolDefaulted} = useSwapTouched() - useEffect(() => { + React.useEffect(() => { if (orderData.selectedPoolId === orderData.bestPoolCalculation?.pool.poolId) poolDefaulted() }, [orderData.selectedPoolId, orderData.bestPoolCalculation, poolDefaulted]) + React.useEffect(() => { + if (isBuyTouched) refetch() + }, [orderData.amounts.sell.tokenId, orderData.amounts.buy.tokenId, refetch, orderData.type, isBuyTouched]) + const {createUnsignedTx, isLoading} = useSwapTx({ onSuccess: (yoroiUnsignedTx) => { unsignedTxChanged(yoroiUnsignedTx) @@ -115,6 +128,18 @@ export const CreateOrder = () => { navigation.confirmTx() } + const createSwapOrder = (orderData: Swap.CreateOrderData) => { + createOrderData({ + amounts: { + sell: orderData.amounts.sell, + buy: orderData.amounts.buy, + }, + address: orderData?.address, + slippage: orderData.slippage, + selectedPool: orderData.selectedPool, + }) + } + const createUnsignedSwapTx = () => { const orderDetails = { sell: orderData.amounts.sell, @@ -150,18 +175,6 @@ export const CreateOrder = () => { } } - const createSwapOrder = (orderData: Swap.CreateOrderData) => { - createOrderData({ - amounts: { - sell: orderData.amounts.sell, - buy: orderData.amounts.buy, - }, - address: orderData?.address, - slippage: orderData.slippage, - selectedPool: orderData.selectedPool, - }) - } - const handleOnSwap = () => { if (orderData.selectedPoolCalculation === undefined) return if (orderData.type === 'limit' && orderData.limitPrice !== undefined) { diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 2be25f6fcb..f8ea6cafe3 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -1,8 +1,8 @@ import {FlashList} from '@shopify/flash-list' -import {useSwap, useSwapPoolsByPair, useSwapTokensByPairToken} from '@yoroi/swap' +import {useSwap, useSwapTokensByPairToken} from '@yoroi/swap' import {Balance} from '@yoroi/types' import React from 'react' -import {InteractionManager, StyleSheet, TouchableOpacity, View} from 'react-native' +import {StyleSheet, TouchableOpacity, View} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import {Boundary, Icon, Spacer, Text} from '../../../../../../../components' @@ -178,41 +178,21 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenForList: TokenForList; wallet: YoroiWallet} const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {buyTokenIdChanged, poolPairsChanged, orderData} = useSwap() + const {buyTokenIdChanged} = useSwap() const {buyTouched} = useSwapTouched() - const {refetch} = useSwapPoolsByPair( - { - tokenA: orderData.amounts.buy.tokenId, - tokenB: orderData.amounts.sell.tokenId, - }, - { - useErrorBoundary: true, - enabled: false, - onSuccess: (pools) => { - buyTouched() - closeSearch() - poolPairsChanged(pools) - - InteractionManager.runAfterInteractions(() => { - navigateTo.startSwap() - }) - }, - }, - ) - - React.useEffect(() => { - refetch() - }, [refetch, orderData.amounts.buy.tokenId]) - const navigateTo = useNavigateTo() const balanceAvailable = useBalance({wallet, tokenId: tokenForList.id}) const {track} = useMetrics() + const onSelect = () => { track.swapAssetToChanged({ to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], }) + buyTouched() buyTokenIdChanged(tokenForList.id) + navigateTo.startSwap() + closeSearch() } return ( diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx index 7c7dcca1c8..cd7c70cb42 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/EditSellAmount.tsx @@ -20,7 +20,7 @@ export const EditSellAmount = () => { const inputRef = React.useRef(null) const {orderData, sellQuantityChanged} = useSwap() - const {isSellTouched} = useSwapTouched() + const {isSellTouched, isBuyTouched} = useSwapTouched() const {tokenId, quantity} = orderData.amounts.sell @@ -37,7 +37,7 @@ export const EditSellAmount = () => { }, [isSellTouched, quantity, tokenInfo.decimals]) const hasBalance = !Quantities.isGreaterThan(quantity, balance) - const showError = !Quantities.isZero(quantity) && !hasBalance + const showError = !Quantities.isZero(quantity) && !hasBalance && isBuyTouched const onChangeQuantity = (text: string) => { try { @@ -60,7 +60,7 @@ export const EditSellAmount = () => { navigateTo={navigate.selectSellToken} touched={isSellTouched} inputRef={inputRef} - inputEditable={orderData.selectedPoolCalculation?.pool !== undefined} + // inputEditable={orderData.selectedPoolCalculation?.pool !== undefined} /> ) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx index 650dcb40ba..d3590eef93 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditSellAmount/SelectSellTokenFromListScreen/SelectSellTokenFromListScreen.tsx @@ -1,8 +1,8 @@ import {FlashList} from '@shopify/flash-list' -import {useSwap, useSwapPoolsByPair} from '@yoroi/swap' +import {useSwap} from '@yoroi/swap' import {Balance} from '@yoroi/types' import React from 'react' -import {InteractionManager, StyleSheet, TouchableOpacity, View} from 'react-native' +import {StyleSheet, TouchableOpacity, View} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' import {Boundary, Spacer, Text} from '../../../../../../../components' @@ -83,42 +83,21 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenInfo: Balance.TokenInfo; wallet: YoroiWallet} const SelectableToken = ({tokenInfo, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {sellTokenIdChanged, poolPairsChanged, orderData} = useSwap() + const {sellTokenIdChanged} = useSwap() const {sellTouched} = useSwapTouched() const navigateTo = useNavigateTo() const {track} = useMetrics() - const {refetch} = useSwapPoolsByPair( - { - tokenA: orderData.amounts.buy.tokenId, - tokenB: orderData.amounts.sell.tokenId, - }, - { - useErrorBoundary: true, - enabled: false, - onSuccess: (pools) => { - sellTouched() - closeSearch() - poolPairsChanged(pools) - - InteractionManager.runAfterInteractions(() => { - navigateTo.startSwap() - }) - }, - }, - ) - - React.useEffect(() => { - refetch() - }, [refetch, orderData.amounts.sell.tokenId]) - const balanceAvailable = useBalance({wallet, tokenId: tokenInfo.id}) const onSelect = () => { track.swapAssetFromChanged({ from_asset: [{asset_name: tokenInfo.name, asset_ticker: tokenInfo.ticker, policy_id: tokenInfo.group}], }) + sellTouched() sellTokenIdChanged(tokenInfo.id) + navigateTo.startSwap() + closeSearch() } return ( diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx index 8f04db9571..004da1926e 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx @@ -13,28 +13,31 @@ import {useSwapTouched} from '../../../../common/SwapFormProvider' export const TopTokenActions = () => { const strings = useStrings() const orderTypeLabels = [strings.marketButton, strings.limitButton] - const {orderData, orderTypeChanged} = useSwap() + const {orderData, orderTypeChanged, poolPairsChanged} = useSwap() const {isBuyTouched, isSellTouched} = useSwapTouched() const isDisabled = !isBuyTouched || !isSellTouched || orderData.selectedPoolCalculation === undefined const orderTypeIndex = orderData.type === 'market' ? 0 : 1 const {refetch, isLoading} = useSwapPoolsByPair({ - tokenA: orderData.amounts.sell.tokenId ?? '', - tokenB: orderData.amounts.buy.tokenId ?? '', + tokenA: orderData.amounts.sell.tokenId, + tokenB: orderData.amounts.buy.tokenId, + }, { + enabled: false, + onSuccess: (pools) => { + poolPairsChanged(pools) + } }) const handleSelectOrderType = (index: number) => { if (index === 0) { - refetch() orderTypeChanged('market') } else { orderTypeChanged('limit') } } - const refresh = () => { + const handleRefresh = () => { refetch() - // limitPriceChanged(orderData.marketPrice) } return ( @@ -45,7 +48,7 @@ export const TopTokenActions = () => { selected={orderTypeIndex} /> - + diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index 7fa3933302..99bb074f3f 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -6,12 +6,12 @@ "start": { "line": 134, "column": 15, - "index": 4170 + "index": 4178 }, "end": { "line": 137, "column": 3, - "index": 4253 + "index": 4261 } }, { @@ -21,12 +21,12 @@ "start": { "line": 138, "column": 18, - "index": 4273 + "index": 4281 }, "end": { "line": 141, "column": 3, - "index": 4362 + "index": 4370 } }, { @@ -36,12 +36,12 @@ "start": { "line": 142, "column": 20, - "index": 4384 + "index": 4392 }, "end": { "line": 145, "column": 3, - "index": 4478 + "index": 4486 } }, { @@ -51,12 +51,12 @@ "start": { "line": 146, "column": 19, - "index": 4499 + "index": 4507 }, "end": { "line": 149, "column": 3, - "index": 4603 + "index": 4611 } }, { @@ -66,12 +66,12 @@ "start": { "line": 150, "column": 10, - "index": 4615 + "index": 4623 }, "end": { "line": 153, "column": 3, - "index": 4730 + "index": 4738 } } ] \ No newline at end of file From bc1f95155b1ad0f5745c08ae481e1d1dcb2b54c5 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 09:20:22 +0100 Subject: [PATCH 32/67] wip: state --- .../CreateOrder/CreateOrder.tsx | 16 +++++++-------- .../EditBuyAmount/EditBuyAmount.tsx | 9 +++++++++ .../SelectBuyTokenFromListScreen.tsx | 2 +- .../Swap/common/AmountCard/AmountCard.json | 20 +++++++++---------- .../src/translators/reactjs/state/state.ts | 2 ++ 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx index 634d5b8eee..7b460e6e0b 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx @@ -31,16 +31,21 @@ const LIMIT_PRICE_WARNING_THRESHOLD = 0.1 // 10% export const CreateOrder = () => { const strings = useStrings() const navigation = useNavigateTo() - const {orderData, unsignedTxChanged} = useSwap() + const {orderData, unsignedTxChanged, poolPairsChanged} = useSwap() const wallet = useSelectedWallet() const {track} = useMetrics() - const {refetch} = useSwapPoolsByPair( + const {isBuyTouched, isSellTouched, poolDefaulted} = useSwapTouched() + + useSwapPoolsByPair( { tokenA: orderData.amounts.sell.tokenId, tokenB: orderData.amounts.buy.tokenId, }, { - enabled: false, + enabled: isBuyTouched, + onSuccess: (pools) => { + poolPairsChanged(pools) + }, }, ) @@ -53,16 +58,11 @@ export const CreateOrder = () => { tokenId: orderData.amounts.buy.tokenId, }) const [showLimitPriceWarning, setShowLimitPriceWarning] = React.useState(false) - const {isBuyTouched, isSellTouched, poolDefaulted} = useSwapTouched() React.useEffect(() => { if (orderData.selectedPoolId === orderData.bestPoolCalculation?.pool.poolId) poolDefaulted() }, [orderData.selectedPoolId, orderData.bestPoolCalculation, poolDefaulted]) - React.useEffect(() => { - if (isBuyTouched) refetch() - }, [orderData.amounts.sell.tokenId, orderData.amounts.buy.tokenId, refetch, orderData.type, isBuyTouched]) - const {createUnsignedTx, isLoading} = useSwapTx({ onSuccess: (yoroiUnsignedTx) => { unsignedTxChanged(yoroiUnsignedTx) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx index bd1b42dc6f..c4fb2b03dd 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx @@ -30,6 +30,15 @@ export const EditBuyAmount = () => { const [inputValue, setInputValue] = React.useState(Quantities.format(quantity, tokenInfo.decimals ?? 0)) React.useEffect(() => { + console.log('EditBuyAmount::useEffect') + console.log( + 'isBuyTouched', + isBuyTouched, + 'inputRef?.current?.isFocused()', + inputRef?.current?.isFocused(), + 'quantity', + quantity, + ) if (isBuyTouched && !inputRef?.current?.isFocused()) { setInputValue(Quantities.format(quantity, tokenInfo.decimals ?? 0)) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index f8ea6cafe3..08807d7685 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -189,8 +189,8 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { track.swapAssetToChanged({ to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], }) - buyTouched() buyTokenIdChanged(tokenForList.id) + buyTouched() navigateTo.startSwap() closeSearch() } diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index 99bb074f3f..7fa3933302 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -6,12 +6,12 @@ "start": { "line": 134, "column": 15, - "index": 4178 + "index": 4170 }, "end": { "line": 137, "column": 3, - "index": 4261 + "index": 4253 } }, { @@ -21,12 +21,12 @@ "start": { "line": 138, "column": 18, - "index": 4281 + "index": 4273 }, "end": { "line": 141, "column": 3, - "index": 4370 + "index": 4362 } }, { @@ -36,12 +36,12 @@ "start": { "line": 142, "column": 20, - "index": 4392 + "index": 4384 }, "end": { "line": 145, "column": 3, - "index": 4486 + "index": 4478 } }, { @@ -51,12 +51,12 @@ "start": { "line": 146, "column": 19, - "index": 4507 + "index": 4499 }, "end": { "line": 149, "column": 3, - "index": 4611 + "index": 4603 } }, { @@ -66,12 +66,12 @@ "start": { "line": 150, "column": 10, - "index": 4623 + "index": 4615 }, "end": { "line": 153, "column": 3, - "index": 4738 + "index": 4730 } } ] \ No newline at end of file diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index cc44e7e794..20c49a90a3 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -423,6 +423,7 @@ const orderReducer = ( pools: state.orderData.pools, primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, + side: 'sell', }) draft.orderData.bestPoolCalculation = getBestPoolCalculation( draft.orderData.calculations, @@ -557,6 +558,7 @@ const orderReducer = ( pools: draft.orderData.pools, primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, + side: 'sell', }) draft.orderData.bestPoolCalculation = getBestPoolCalculation( draft.orderData.calculations, From c41fea92401034b2144248fb1463ee983037d311 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:36:20 +0100 Subject: [PATCH 33/67] chore: effects --- .../SelectPoolFromList.stories.tsx | 2 +- .../SelectPoolFromList/SelectPoolFromList.tsx | 6 +++--- .../SelectBuyTokenFromListScreen.tsx | 1 - .../SelectPoolFromListScreen.tsx | 12 +++++------ .../CreateOrder/EditPool/ShowPoolActions.tsx | 11 +++++----- .../ShowTokenActions/ClearQuantities.tsx | 9 +++++++- .../ShowTokenActions/TopTokenActions.tsx | 21 +++++++++++-------- .../src/translators/reactjs/state/state.ts | 13 +++++++----- 8 files changed, 42 insertions(+), 33 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx index 24f5de36b7..9fff3c8c8e 100644 --- a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx @@ -14,7 +14,7 @@ storiesOf('Swap List Pool', module) .addDecorator((story) => {story()}) .add('initial', () => ( } -export const SelectPoolFromList = ({data = []}: Props) => { +export const SelectPoolFromList = ({pools = []}: Props) => { const strings = useStrings() const wallet = useSelectedWallet() const {selectedPoolChanged, orderData} = useSwap() @@ -37,7 +37,7 @@ export const SelectPoolFromList = ({data = []}: Props) => { return ( - {data.map((pool) => ( + {pools.map((pool) => ( diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 08807d7685..8588dcc76e 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -184,7 +184,6 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { const balanceAvailable = useBalance({wallet, tokenId: tokenForList.id}) const {track} = useMetrics() - const onSelect = () => { track.swapAssetToChanged({ to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx index 587c83cc58..f6017ea6c7 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/SelectPoolFromListScreen/SelectPoolFromListScreen.tsx @@ -1,4 +1,4 @@ -import {useSwap, useSwapPoolsByPair} from '@yoroi/swap' +import {useSwap} from '@yoroi/swap' import React from 'react' import {ScrollView} from 'react-native' import {SafeAreaView} from 'react-native-safe-area-context' @@ -12,16 +12,14 @@ export const SelectPoolFromListScreen = () => { const strings = useStrings() const {orderData} = useSwap() - const {poolList} = useSwapPoolsByPair({ - tokenA: orderData.amounts.sell.tokenId, - tokenB: orderData.amounts.buy.tokenId, - }) - const poolCounter = Array.isArray(poolList) ? poolList.length : 0 + const {pools} = orderData + + const poolCounter = Array.isArray(pools) ? pools.length : 0 return ( - + diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx index 6d581bd908..9a15564560 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx @@ -56,7 +56,8 @@ export const ShowPoolActions = () => { const poolStatus = orderData.type === 'limit' && isPoolTouched ? '' : ` ${strings.autoPool}` const poolTitle = `${poolProviderFormatted}${poolStatus}` - const handlePress = () => setHiddenInfoOpenId(hiddenInfoOpenId !== id ? id : null) + const handleOnExpand = () => setHiddenInfoOpenId(hiddenInfoOpenId !== id ? id : null) + const handleOnChangePool = () => navigateTo.selectPool() return ( @@ -70,7 +71,7 @@ export const ShowPoolActions = () => { {orderData.type === 'limit' && ( - navigateTo.selectPool()}> + {strings.changePool} )} @@ -79,10 +80,8 @@ export const ShowPoolActions = () => { - - {header} - + + {header} } info={ diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx index 3c1cd3461f..28c49f79e6 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx @@ -5,13 +5,20 @@ import {TouchableOpacity} from 'react-native-gesture-handler' import {COLORS} from '../../../../../../theme' import {useStrings} from '../../../../common/strings' +import {useSwapTouched} from '../../../../common/SwapFormProvider' export const ClearQuantities = () => { const strings = useStrings() const {resetQuantities} = useSwap() + const {poolDefaulted} = useSwapTouched() + + const handleReset = () => { + resetQuantities() + poolDefaulted() + } return ( - + {strings.clear} ) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx index 004da1926e..561123cbc4 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx @@ -18,15 +18,18 @@ export const TopTokenActions = () => { const isDisabled = !isBuyTouched || !isSellTouched || orderData.selectedPoolCalculation === undefined const orderTypeIndex = orderData.type === 'market' ? 0 : 1 - const {refetch, isLoading} = useSwapPoolsByPair({ - tokenA: orderData.amounts.sell.tokenId, - tokenB: orderData.amounts.buy.tokenId, - }, { - enabled: false, - onSuccess: (pools) => { - poolPairsChanged(pools) - } - }) + const {refetch, isLoading} = useSwapPoolsByPair( + { + tokenA: orderData.amounts.sell.tokenId, + tokenB: orderData.amounts.buy.tokenId, + }, + { + enabled: false, + onSuccess: (pools) => { + poolPairsChanged(pools) + }, + }, + ) const handleSelectOrderType = (index: number) => { if (index === 0) { diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index 20c49a90a3..d3e3e5191c 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -272,6 +272,7 @@ const orderReducer = ( pools: state.orderData.pools, primaryTokenId: state.orderData.primartyTokenId, lpTokenHeld: state.orderData.lpTokenHeld, + side: 'sell', }) draft.orderData.bestPoolCalculation = getBestPoolCalculation( draft.orderData.calculations, @@ -298,7 +299,7 @@ const orderReducer = ( // it ignores events if order type is not limit // NOTE: late it can replace the order from market to limit and recalc case SwapCreateOrderActionType.SelectedPoolChanged: - if (state.orderData.type !== 'limit') break + if (state.orderData.type === 'market') break draft.orderData.selectedPoolId = action.poolId @@ -329,7 +330,6 @@ const orderReducer = ( ) draft.orderData.selectedPoolCalculation = selectedPoolCalculationSelector(draft.orderData) - break // when switching and the type is limit can end up with weird amounts @@ -371,6 +371,7 @@ const orderReducer = ( break // when resetting quantities, when order is limit, limit price is the best market price + // also resets the selected pool, otherwise users will need to leave the funnel // otherwise the limit set back to undefined case SwapCreateOrderActionType.ResetQuantities: draft.orderData.amounts = { @@ -383,11 +384,13 @@ const orderReducer = ( tokenId: state.orderData.amounts.buy.tokenId, }, } + draft.orderData.selectedPoolId = undefined + draft.orderData.limitPrice = undefined draft.orderData.calculations = makeOrderCalculations({ - orderType: state.orderData.type, + orderType: 'market', amounts: draft.orderData.amounts, - limitPrice: state.orderData.limitPrice, + limitPrice: undefined, slippage: state.orderData.slippage, pools: state.orderData.pools, primaryTokenId: state.orderData.primartyTokenId, @@ -413,7 +416,7 @@ const orderReducer = ( case SwapCreateOrderActionType.LimitPriceChanged: draft.orderData.limitPrice = action.limitPrice - if (state.orderData.type !== 'limit') break + if (state.orderData.type === 'market') break draft.orderData.calculations = makeOrderCalculations({ orderType: state.orderData.type, From b3fee3935fa9a9691c2eaf75c9c35a6ba56c9610 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:26:40 +0100 Subject: [PATCH 34/67] wip: clean ups - get pt price --- .../SelectPoolFromList.stories.tsx | 2 - .../SelectPoolFromList/SelectPoolFromList.tsx | 135 +++++++++++------- .../src/features/Swap/common/mocks.ts | 1 - .../wallet-mobile/src/i18n/locales/en-US.json | 2 +- .../src/adapters/openswap-api/api.mocks.ts | 4 - packages/swap/src/helpers/mocks.ts | 36 ----- .../orders/{ => amounts}/getBuyAmount.test.ts | 0 .../orders/{ => amounts}/getBuyAmount.ts | 6 +- .../getMinAdaReceiveAfterSlippage.test.ts | 4 +- .../getMinAdaReceiveAfterSlippage.ts | 4 +- .../getQuantityWithSlippage.test.ts | 0 .../{ => amounts}/getQuantityWithSlippage.ts | 4 +- .../{ => amounts}/getSellAmount.test.ts | 0 .../orders/{ => amounts}/getSellAmount.ts | 6 +- .../orders/{ => costs}/getFrontendFee.test.ts | 6 +- .../orders/{ => costs}/getFrontendFee.ts | 6 +- .../getLiquidityProviderFee.test.ts | 4 +- .../{ => costs}/getLiquidityProviderFee.ts | 6 +- .../{ => factories}/makeLimitOrder.test.ts | 5 +- .../orders/{ => factories}/makeLimitOrder.ts | 2 +- .../{ => factories}/makeOrderCalculations.ts | 18 +-- .../makePossibleMarketOrder.test.ts | 2 - .../makePossibleMarketOrder.ts | 4 +- .../src/helpers/pools/getBestBuyPool.test.ts | 2 +- .../swap/src/helpers/pools/getBestBuyPool.ts | 4 +- .../src/helpers/pools/getBestSellPool.test.ts | 2 +- .../swap/src/helpers/pools/getBestSellPool.ts | 4 +- .../{orders => prices}/getMarketPrice.test.ts | 0 .../{orders => prices}/getMarketPrice.ts | 0 .../prices/getPairPriceInPtTerms.test.ts | 58 ++++++++ .../helpers/prices/getPairPriceInPtTerms.ts | 49 +++++++ .../getPriceAfterFee.test.ts | 4 - .../{orders => prices}/getPriceAfterFee.ts | 0 packages/swap/src/helpers/transformers.ts | 1 - packages/swap/src/index.ts | 52 ++++--- .../src/translators/reactjs/state/state.ts | 2 +- packages/types/src/swap/pool.ts | 1 - 37 files changed, 272 insertions(+), 164 deletions(-) rename packages/swap/src/helpers/orders/{ => amounts}/getBuyAmount.test.ts (100%) rename packages/swap/src/helpers/orders/{ => amounts}/getBuyAmount.ts (89%) rename packages/swap/src/helpers/orders/{ => amounts}/getMinAdaReceiveAfterSlippage.test.ts (88%) rename packages/swap/src/helpers/orders/{ => amounts}/getMinAdaReceiveAfterSlippage.ts (90%) rename packages/swap/src/helpers/orders/{ => amounts}/getQuantityWithSlippage.test.ts (100%) rename packages/swap/src/helpers/orders/{ => amounts}/getQuantityWithSlippage.ts (80%) rename packages/swap/src/helpers/orders/{ => amounts}/getSellAmount.test.ts (100%) rename packages/swap/src/helpers/orders/{ => amounts}/getSellAmount.ts (90%) rename packages/swap/src/helpers/orders/{ => costs}/getFrontendFee.test.ts (98%) rename packages/swap/src/helpers/orders/{ => costs}/getFrontendFee.ts (95%) rename packages/swap/src/helpers/orders/{ => costs}/getLiquidityProviderFee.test.ts (90%) rename packages/swap/src/helpers/orders/{ => costs}/getLiquidityProviderFee.ts (73%) rename packages/swap/src/helpers/orders/{ => factories}/makeLimitOrder.test.ts (96%) rename packages/swap/src/helpers/orders/{ => factories}/makeLimitOrder.ts (92%) rename packages/swap/src/helpers/orders/{ => factories}/makeOrderCalculations.ts (91%) rename packages/swap/src/helpers/orders/{ => factories}/makePossibleMarketOrder.test.ts (98%) rename packages/swap/src/helpers/orders/{ => factories}/makePossibleMarketOrder.ts (92%) rename packages/swap/src/helpers/{orders => prices}/getMarketPrice.test.ts (100%) rename packages/swap/src/helpers/{orders => prices}/getMarketPrice.ts (100%) create mode 100644 packages/swap/src/helpers/prices/getPairPriceInPtTerms.test.ts create mode 100644 packages/swap/src/helpers/prices/getPairPriceInPtTerms.ts rename packages/swap/src/helpers/{orders => prices}/getPriceAfterFee.test.ts (98%) rename packages/swap/src/helpers/{orders => prices}/getPriceAfterFee.ts (100%) diff --git a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx index 9fff3c8c8e..48a824efb8 100644 --- a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.stories.tsx @@ -22,7 +22,6 @@ storiesOf('Swap List Pool', module) ptPriceTokenB: '0', fee: '0.3', // 0.3% provider: 'minswap', - price: 2, batcherFee: {quantity: '1', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', @@ -38,7 +37,6 @@ storiesOf('Swap List Pool', module) ptPriceTokenB: '0', fee: '0.3', // 0.3% provider: 'sundaeswap', - price: 6, batcherFee: {quantity: '122', tokenId: ''}, deposit: {quantity: '432', tokenId: ''}, poolId: '23455', diff --git a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx index 1b7580abcf..761f768943 100644 --- a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx @@ -1,13 +1,17 @@ import {useSwap} from '@yoroi/swap' -import {Swap} from '@yoroi/types' +import {Balance, Swap} from '@yoroi/types' +import BigNumber from 'bignumber.js' import React, {useState} from 'react' import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' import LinearGradient from 'react-native-linear-gradient' -import {Spacer} from '../../../../../components' +import {Boundary, Spacer} from '../../../../../components' import {useMetrics} from '../../../../../metrics/metricsManager' import {useSelectedWallet} from '../../../../../SelectedWallet' import {COLORS} from '../../../../../theme' +import {YoroiWallet} from '../../../../../yoroi-wallets/cardano/types' +import {useTokenInfo} from '../../../../../yoroi-wallets/hooks' +import {Quantities} from '../../../../../yoroi-wallets/utils' import {useNavigateTo} from '../../navigation' import {PoolIcon} from '../../PoolIcon/PoolIcon' import {useStrings} from '../../strings' @@ -33,74 +37,109 @@ export const SelectPoolFromList = ({pools = []}: Props) => { navigate.startSwap() } + const decimals = wallet.primaryTokenInfo.decimals ?? 0 + const ticker = wallet.primaryTokenInfo.ticker + const protocolCapitalize = (protocol: string): string => protocol[0].toUpperCase() + protocol.substring(1) return ( - {pools.map((pool) => ( - - - - - - handleCardSelect(pool)} style={[styles.card]}> - - - - - - {protocolCapitalize(pool.provider)} - + {pools.map((pool) => { + const formattedDepositInPt = `${Quantities.format(pool.deposit.quantity, decimals, decimals)} ${ticker}` + const formattedBatcherFeeInPt = `${Quantities.format(pool.batcherFee.quantity, decimals, decimals)} ${ticker}` + + return ( + + + + + + handleCardSelect(pool)} style={[styles.card]}> + + + + - - - + {protocolCapitalize(pool.provider)} + - - {strings.price} + + + - {`${pool.price} ${wallet.primaryTokenInfo.ticker}`} + + + - - - + + - - {`${strings.tvl}, ${wallet.primaryTokenInfo.ticker}`} + + {`${strings.tvl}, ${wallet.primaryTokenInfo.ticker}`} - {pool.deposit.quantity} + {formattedDepositInPt} + - - - + + - - {strings.poolFee}, % + + {strings.poolFee}, % - {pool.fee}% + {pool.fee}% + - - - + + - - {`${strings.batcherFee}, ${wallet.primaryTokenInfo.ticker}`} + + {`${strings.batcherFee}, ${wallet.primaryTokenInfo.ticker}`} - {pool.batcherFee.quantity} + {formattedBatcherFeeInPt} + - - - + + + - - ))} + ) + })} + + ) +} + +type PriceInAdaProps = {pool: Swap.Pool; wallet: YoroiWallet; sell: Balance.Amount} +const PriceInAda = ({pool, wallet, sell}: PriceInAdaProps) => { + const strings = useStrings() + + const {decimals: decimalsA = 0}= useTokenInfo({wallet, tokenId: pool.tokenA.tokenId}) + const {decimals: decimalsB = 0}= useTokenInfo({wallet, tokenId: pool.tokenB.tokenId}) + + const scaleA = new BigNumber(10).pow(decimalsA) + const scaleB = new BigNumber(10).pow(decimalsB) + + const isSellTokenA = pool.tokenA.tokenId === sell.tokenId + const [dividend, divisor] = isSellTokenA + ? [new BigNumber(pool.ptPriceTokenB).multipliedBy(scaleB), new BigNumber(pool.ptPriceTokenA).multipliedBy(scaleA)] + : [new BigNumber(pool.ptPriceTokenA).multipliedBy(scaleA), new BigNumber(pool.ptPriceTokenB).multipliedBy(scaleB)] + // limit decimals + const ptPrice = divisor.isZero() ? '0' : dividend.dividedBy(divisor).toFixed(Math.max(decimalsA, decimalsB), BigNumber.ROUND_DOWN) + // const price = parsedPrice != null ? asQuantity(parsedPrice) : Quantities.zero + // const formattedPriceInPt = `${Quantities.format(price, 0, decimals)} ${ticker}` + return ( + + {strings.price} + + {ptPrice} ) } diff --git a/apps/wallet-mobile/src/features/Swap/common/mocks.ts b/apps/wallet-mobile/src/features/Swap/common/mocks.ts index b204b3c578..ac93729850 100644 --- a/apps/wallet-mobile/src/features/Swap/common/mocks.ts +++ b/apps/wallet-mobile/src/features/Swap/common/mocks.ts @@ -28,7 +28,6 @@ export const mocks = { tokenId: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.6c702083', }, poolId: '0029cb7c88c7567b63d1a512c0ed626aa169688ec980730c0473b913.702083', - price: 0.0890390378168252, provider: 'sundaeswap', tokenA: {quantity: asQuantity(20630071), tokenId: ''}, tokenB: { diff --git a/apps/wallet-mobile/src/i18n/locales/en-US.json b/apps/wallet-mobile/src/i18n/locales/en-US.json index 74fa00e732..21b3eed28c 100644 --- a/apps/wallet-mobile/src/i18n/locales/en-US.json +++ b/apps/wallet-mobile/src/i18n/locales/en-US.json @@ -168,7 +168,7 @@ "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/packages/swap/src/adapters/openswap-api/api.mocks.ts b/packages/swap/src/adapters/openswap-api/api.mocks.ts index a38ee77bca..29b8166095 100644 --- a/packages/swap/src/adapters/openswap-api/api.mocks.ts +++ b/packages/swap/src/adapters/openswap-api/api.mocks.ts @@ -41,7 +41,6 @@ const createOrderData: Swap.CreateOrderData = { tokenB: {tokenId: '', quantity: '1000000000'}, ptPriceTokenA: '0', ptPriceTokenB: '0', - price: 0, batcherFee: {tokenId: '', quantity: '0'}, deposit: {tokenId: '', quantity: '2000000'}, poolId: @@ -78,7 +77,6 @@ const getPools: Swap.Pool[] = [ }, batcherFee: {quantity: '2000000', tokenId: ''}, fee: '0.3', - price: 0, poolId: '0be55d262b29f564998ff81efe21bdc0022621c12f15af08d0f2ddb1.7339a8bcda85e2c997d9f16beddbeb3ad755f5202f5cfd9cb08db346a1292c01', provider: 'minswap', @@ -100,7 +98,6 @@ const getPools: Swap.Pool[] = [ }, batcherFee: {quantity: '2000000', tokenId: ''}, fee: '0.3', - price: 0, poolId: '0be55d262b29f564998ff81efe21bdc0022621c12f15af08d0f2ddb1.7339a8bcda85e2c997d9f16beddbeb3ad755f5202f5cfd9cb08db346a1292c01', provider: 'sundaeswap', @@ -122,7 +119,6 @@ const getPools: Swap.Pool[] = [ }, batcherFee: {quantity: '2000000', tokenId: ''}, fee: '0.3', - price: 0, poolId: '0be55d262b29f564998ff81efe21bdc0022621c12f15af08d0f2ddb1.7339a8bcda85e2c997d9f16beddbeb3ad755f5202f5cfd9cb08db346a1292c01', provider: 'sundaeswap', diff --git a/packages/swap/src/helpers/mocks.ts b/packages/swap/src/helpers/mocks.ts index 2092fb7cde..a93eed89b0 100644 --- a/packages/swap/src/helpers/mocks.ts +++ b/packages/swap/src/helpers/mocks.ts @@ -9,7 +9,6 @@ const mockedPools1: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'muesliswap_v2', - price: 0, batcherFee: {quantity: '950000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '1', @@ -25,7 +24,6 @@ const mockedPools1: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'vyfi', - price: 0, batcherFee: {quantity: '1900000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '2', @@ -41,7 +39,6 @@ const mockedPools1: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'minswap', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '3', @@ -57,7 +54,6 @@ const mockedPools1: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.35', // 0.35% provider: 'wingriders', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '4', @@ -73,7 +69,6 @@ const mockedPools1: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '5', @@ -89,7 +84,6 @@ const mockedPools1: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.05', // 0.05% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '6', @@ -108,7 +102,6 @@ const mockedPools2: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'muesliswap_v2', - price: 0, batcherFee: {quantity: '950000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -125,7 +118,6 @@ const mockedPools2: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'vyfi', - price: 0, batcherFee: {quantity: '1900000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -142,7 +134,6 @@ const mockedPools2: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'minswap', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -159,7 +150,6 @@ const mockedPools2: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.35', // 0.35% provider: 'wingriders', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -176,7 +166,6 @@ const mockedPools2: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', // 0.3% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -193,7 +182,6 @@ const mockedPools2: Swap.Pool[] = [ ptPriceTokenB: '0.0695404765', fee: '0.05', // 0.05% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -211,7 +199,6 @@ const mockedPools3: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.3', // 0.3% provider: 'muesliswap_v2', - price: 0, batcherFee: {quantity: '950000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -227,7 +214,6 @@ const mockedPools3: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.3', // 0.3% provider: 'vyfi', - price: 0, batcherFee: {quantity: '1900000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -243,7 +229,6 @@ const mockedPools3: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.3', // 0.3% provider: 'minswap', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -259,7 +244,6 @@ const mockedPools3: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.35', // 0.35% provider: 'wingriders', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -275,7 +259,6 @@ const mockedPools3: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.3', // 0.3% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -291,7 +274,6 @@ const mockedPools3: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.05', // 0.05% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -309,7 +291,6 @@ const mockedPools4: Swap.Pool[] = [ ptPriceTokenA: '0.06950020009', fee: '0.3', // 0.3% provider: 'muesliswap_v2', - price: 0, batcherFee: {quantity: '950000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -325,7 +306,6 @@ const mockedPools4: Swap.Pool[] = [ ptPriceTokenA: '0.06950020009', fee: '0.3', // 0.3% provider: 'vyfi', - price: 0, batcherFee: {quantity: '1900000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -341,7 +321,6 @@ const mockedPools4: Swap.Pool[] = [ ptPriceTokenA: '0.06950020009', fee: '0.3', // 0.3% provider: 'minswap', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -357,7 +336,6 @@ const mockedPools4: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.35', // 0.35% provider: 'wingriders', - price: 0, batcherFee: {quantity: '2000000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -373,7 +351,6 @@ const mockedPools4: Swap.Pool[] = [ ptPriceTokenA: '0.06950020009', fee: '0.3', // 0.3% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -389,7 +366,6 @@ const mockedPools4: Swap.Pool[] = [ ptPriceTokenB: '0.06950020009', fee: '0.05', // 0.05% provider: 'sundaeswap', - price: 0, batcherFee: {quantity: '2500000', tokenId: ''}, deposit: {quantity: '2000000', tokenId: ''}, poolId: '0', @@ -483,7 +459,6 @@ const mockedOrderCalculations1: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'muesliswap_v2', - price: 0, batcherFee: { quantity: '950000', tokenId: '', @@ -581,7 +556,6 @@ const mockedOrderCalculations1: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'vyfi', - price: 0, batcherFee: { quantity: '1900000', tokenId: '', @@ -679,7 +653,6 @@ const mockedOrderCalculations1: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'minswap', - price: 0, batcherFee: { quantity: '2000000', tokenId: '', @@ -777,7 +750,6 @@ const mockedOrderCalculations1: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.35', provider: 'wingriders', - price: 0, batcherFee: { quantity: '2000000', tokenId: '', @@ -875,7 +847,6 @@ const mockedOrderCalculations1: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'sundaeswap', - price: 0, batcherFee: { quantity: '2500000', tokenId: '', @@ -973,7 +944,6 @@ const mockedOrderCalculations1: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.05', provider: 'sundaeswap', - price: 0, batcherFee: { quantity: '2500000', tokenId: '', @@ -1067,7 +1037,6 @@ const mockedOrderCalculations2: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'muesliswap_v2', - price: 0, batcherFee: { quantity: '950000', tokenId: '', @@ -1158,7 +1127,6 @@ const mockedOrderCalculations2: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'vyfi', - price: 0, batcherFee: { quantity: '1900000', tokenId: '', @@ -1249,7 +1217,6 @@ const mockedOrderCalculations2: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'minswap', - price: 0, batcherFee: { quantity: '2000000', tokenId: '', @@ -1340,7 +1307,6 @@ const mockedOrderCalculations2: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.35', provider: 'wingriders', - price: 0, batcherFee: { quantity: '2000000', tokenId: '', @@ -1431,7 +1397,6 @@ const mockedOrderCalculations2: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.3', provider: 'sundaeswap', - price: 0, batcherFee: { quantity: '2500000', tokenId: '', @@ -1522,7 +1487,6 @@ const mockedOrderCalculations2: SwapOrderCalculation[] = [ ptPriceTokenB: '0.0695404765', fee: '0.05', provider: 'sundaeswap', - price: 0, batcherFee: { quantity: '2500000', tokenId: '', diff --git a/packages/swap/src/helpers/orders/getBuyAmount.test.ts b/packages/swap/src/helpers/orders/amounts/getBuyAmount.test.ts similarity index 100% rename from packages/swap/src/helpers/orders/getBuyAmount.test.ts rename to packages/swap/src/helpers/orders/amounts/getBuyAmount.test.ts diff --git a/packages/swap/src/helpers/orders/getBuyAmount.ts b/packages/swap/src/helpers/orders/amounts/getBuyAmount.ts similarity index 89% rename from packages/swap/src/helpers/orders/getBuyAmount.ts rename to packages/swap/src/helpers/orders/amounts/getBuyAmount.ts index 97a746d963..d9c234d68c 100644 --- a/packages/swap/src/helpers/orders/getBuyAmount.ts +++ b/packages/swap/src/helpers/orders/amounts/getBuyAmount.ts @@ -1,9 +1,9 @@ import BigNumber from 'bignumber.js' import {Balance, Swap} from '@yoroi/types' -import {ceilDivision} from '../../utils/ceilDivision' -import {Quantities} from '../../utils/quantities' -import {asQuantity} from '../../utils/asQuantity' +import {ceilDivision} from '../../../utils/ceilDivision' +import {Quantities} from '../../../utils/quantities' +import {asQuantity} from '../../../utils/asQuantity' /** * Calculate the amount to buy based on the desired sell amount in a liquidity pool. diff --git a/packages/swap/src/helpers/orders/getMinAdaReceiveAfterSlippage.test.ts b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts similarity index 88% rename from packages/swap/src/helpers/orders/getMinAdaReceiveAfterSlippage.test.ts rename to packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts index 04bada4c1a..d0ac842251 100644 --- a/packages/swap/src/helpers/orders/getMinAdaReceiveAfterSlippage.test.ts +++ b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts @@ -1,5 +1,5 @@ -import {mockNumberLocale} from '../../adapters/intl/number-locale.mocks' -import {asQuantity} from '../../utils/asQuantity' +import {mockNumberLocale} from '../../../adapters/intl/number-locale.mocks' +import {asQuantity} from '../../../utils/asQuantity' import {getMinAdaReceiveAfterSlippage} from './getMinAdaReceiveAfterSlippage' describe('getMinAdaReceiveAfterSlippage', () => { diff --git a/packages/swap/src/helpers/orders/getMinAdaReceiveAfterSlippage.ts b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts similarity index 90% rename from packages/swap/src/helpers/orders/getMinAdaReceiveAfterSlippage.ts rename to packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts index 1eb61d5549..828abc1b15 100644 --- a/packages/swap/src/helpers/orders/getMinAdaReceiveAfterSlippage.ts +++ b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts @@ -1,6 +1,6 @@ import {Balance, Numbers} from '@yoroi/types' -import {Quantities} from '../../utils/quantities' -import {asQuantity} from '../../utils/asQuantity' +import {Quantities} from '../../../utils/quantities' +import {asQuantity} from '../../../utils/asQuantity' /** * Calculate the minimum amount of ADA received after accounting for slippage. diff --git a/packages/swap/src/helpers/orders/getQuantityWithSlippage.test.ts b/packages/swap/src/helpers/orders/amounts/getQuantityWithSlippage.test.ts similarity index 100% rename from packages/swap/src/helpers/orders/getQuantityWithSlippage.test.ts rename to packages/swap/src/helpers/orders/amounts/getQuantityWithSlippage.test.ts diff --git a/packages/swap/src/helpers/orders/getQuantityWithSlippage.ts b/packages/swap/src/helpers/orders/amounts/getQuantityWithSlippage.ts similarity index 80% rename from packages/swap/src/helpers/orders/getQuantityWithSlippage.ts rename to packages/swap/src/helpers/orders/amounts/getQuantityWithSlippage.ts index 6e50762b59..15c55cd18f 100644 --- a/packages/swap/src/helpers/orders/getQuantityWithSlippage.ts +++ b/packages/swap/src/helpers/orders/amounts/getQuantityWithSlippage.ts @@ -1,6 +1,6 @@ import {Balance} from '@yoroi/types' -import {ceilDivision} from '../../utils/ceilDivision' -import {asQuantity} from '../../utils/asQuantity' +import {ceilDivision} from '../../../utils/ceilDivision' +import {asQuantity} from '../../../utils/asQuantity' export const getQuantityWithSlippage = ( quantity: Balance.Quantity, diff --git a/packages/swap/src/helpers/orders/getSellAmount.test.ts b/packages/swap/src/helpers/orders/amounts/getSellAmount.test.ts similarity index 100% rename from packages/swap/src/helpers/orders/getSellAmount.test.ts rename to packages/swap/src/helpers/orders/amounts/getSellAmount.test.ts diff --git a/packages/swap/src/helpers/orders/getSellAmount.ts b/packages/swap/src/helpers/orders/amounts/getSellAmount.ts similarity index 90% rename from packages/swap/src/helpers/orders/getSellAmount.ts rename to packages/swap/src/helpers/orders/amounts/getSellAmount.ts index 34b985ba1a..38c1ee0e60 100644 --- a/packages/swap/src/helpers/orders/getSellAmount.ts +++ b/packages/swap/src/helpers/orders/amounts/getSellAmount.ts @@ -1,9 +1,9 @@ import BigNumber from 'bignumber.js' import {Balance, Swap} from '@yoroi/types' -import {ceilDivision} from '../../utils/ceilDivision' -import {Quantities} from '../../utils/quantities' -import {asQuantity} from '../../utils/asQuantity' +import {ceilDivision} from '../../../utils/ceilDivision' +import {Quantities} from '../../../utils/quantities' +import {asQuantity} from '../../../utils/asQuantity' /** * Calculate the amount to sell based on the desired buy amount in a liquidity pool. diff --git a/packages/swap/src/helpers/orders/getFrontendFee.test.ts b/packages/swap/src/helpers/orders/costs/getFrontendFee.test.ts similarity index 98% rename from packages/swap/src/helpers/orders/getFrontendFee.test.ts rename to packages/swap/src/helpers/orders/costs/getFrontendFee.test.ts index 001724a096..4801478704 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.test.ts +++ b/packages/swap/src/helpers/orders/costs/getFrontendFee.test.ts @@ -1,9 +1,9 @@ import {Balance} from '@yoroi/types' import {getFrontendFee} from './getFrontendFee' -import {milkHoldersDiscountTiers} from '../../translators/constants' -import {Quantities} from '../../utils/quantities' -import {asQuantity} from '../../utils/asQuantity' +import {milkHoldersDiscountTiers} from '../../../translators/constants' +import {Quantities} from '../../../utils/quantities' +import {asQuantity} from '../../../utils/asQuantity' describe('getFrontendFee', () => { const primaryTokenId = 'primary.token' diff --git a/packages/swap/src/helpers/orders/getFrontendFee.ts b/packages/swap/src/helpers/orders/costs/getFrontendFee.ts similarity index 95% rename from packages/swap/src/helpers/orders/getFrontendFee.ts rename to packages/swap/src/helpers/orders/costs/getFrontendFee.ts index 8dd09d8eb1..e66874c901 100644 --- a/packages/swap/src/helpers/orders/getFrontendFee.ts +++ b/packages/swap/src/helpers/orders/costs/getFrontendFee.ts @@ -1,12 +1,12 @@ import {Balance} from '@yoroi/types' import BigNumber from 'bignumber.js' -import {Quantities} from '../../utils/quantities' +import {Quantities} from '../../../utils/quantities' import { SwapDiscountTier, milkHoldersDiscountTiers, -} from '../../translators/constants' -import {asQuantity} from '../../utils/asQuantity' +} from '../../../translators/constants' +import {asQuantity} from '../../../utils/asQuantity' /** * Calculates the frontend fee and selects a discount tier for a swap transaction. diff --git a/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts b/packages/swap/src/helpers/orders/costs/getLiquidityProviderFee.test.ts similarity index 90% rename from packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts rename to packages/swap/src/helpers/orders/costs/getLiquidityProviderFee.test.ts index 63ccc03b78..ec2584c8f7 100644 --- a/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts +++ b/packages/swap/src/helpers/orders/costs/getLiquidityProviderFee.test.ts @@ -1,6 +1,6 @@ -import {Quantities} from '../../utils/quantities' +import {Quantities} from '../../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' -import {asQuantity} from '../../utils/asQuantity' +import {asQuantity} from '../../../utils/asQuantity' describe('getLiquidityProviderFee', () => { it('should return zero when sell quantity is zero', () => { diff --git a/packages/swap/src/helpers/orders/getLiquidityProviderFee.ts b/packages/swap/src/helpers/orders/costs/getLiquidityProviderFee.ts similarity index 73% rename from packages/swap/src/helpers/orders/getLiquidityProviderFee.ts rename to packages/swap/src/helpers/orders/costs/getLiquidityProviderFee.ts index 62f790e2ad..b3018b98b4 100644 --- a/packages/swap/src/helpers/orders/getLiquidityProviderFee.ts +++ b/packages/swap/src/helpers/orders/costs/getLiquidityProviderFee.ts @@ -1,7 +1,7 @@ import {Balance} from '@yoroi/types' -import {Quantities} from '../../utils/quantities' -import {ceilDivision} from '../../utils/ceilDivision' -import {asQuantity} from '../../utils/asQuantity' +import {Quantities} from '../../../utils/quantities' +import {ceilDivision} from '../../../utils/ceilDivision' +import {asQuantity} from '../../../utils/asQuantity' export const getLiquidityProviderFee = ( poolFee: string, diff --git a/packages/swap/src/helpers/orders/makeLimitOrder.test.ts b/packages/swap/src/helpers/orders/factories/makeLimitOrder.test.ts similarity index 96% rename from packages/swap/src/helpers/orders/makeLimitOrder.test.ts rename to packages/swap/src/helpers/orders/factories/makeLimitOrder.test.ts index 3e484d5f45..e104036cfa 100644 --- a/packages/swap/src/helpers/orders/makeLimitOrder.test.ts +++ b/packages/swap/src/helpers/orders/factories/makeLimitOrder.test.ts @@ -14,11 +14,10 @@ describe('makeLimitOrder', () => { const pool: Swap.Pool = { tokenA: {quantity: '4500000', tokenId: 'tokenA'}, tokenB: {quantity: '9000000', tokenId: 'tokenB'}, - ptPriceTokenA: '0', - ptPriceTokenB: '0', + ptPriceTokenA: '1', + ptPriceTokenB: '0.5', fee: '0.3', provider: 'minswap', - price: 2, batcherFee: {quantity: '1', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', diff --git a/packages/swap/src/helpers/orders/makeLimitOrder.ts b/packages/swap/src/helpers/orders/factories/makeLimitOrder.ts similarity index 92% rename from packages/swap/src/helpers/orders/makeLimitOrder.ts rename to packages/swap/src/helpers/orders/factories/makeLimitOrder.ts index 9d1d5c6be6..bd19798232 100644 --- a/packages/swap/src/helpers/orders/makeLimitOrder.ts +++ b/packages/swap/src/helpers/orders/factories/makeLimitOrder.ts @@ -1,5 +1,5 @@ import {Balance, Swap} from '@yoroi/types' -import {getQuantityWithSlippage} from './getQuantityWithSlippage' +import {getQuantityWithSlippage} from '../amounts/getQuantityWithSlippage' /** * Create a limit order with specified parameters. diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/factories/makeOrderCalculations.ts similarity index 91% rename from packages/swap/src/helpers/orders/makeOrderCalculations.ts rename to packages/swap/src/helpers/orders/factories/makeOrderCalculations.ts index 8f555035ef..1e38b5d8a2 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/factories/makeOrderCalculations.ts @@ -1,14 +1,14 @@ import {Balance, Swap} from '@yoroi/types' import {BigNumber} from 'bignumber.js' -import {SwapOrderCalculation} from '../../translators/reactjs/state/state' -import {getQuantityWithSlippage} from './getQuantityWithSlippage' -import {getLiquidityProviderFee} from './getLiquidityProviderFee' -import {getFrontendFee} from './getFrontendFee' -import {getMarketPrice} from './getMarketPrice' -import {getBuyAmount} from './getBuyAmount' -import {getSellAmount} from './getSellAmount' -import {asQuantity} from '../../utils/asQuantity' -import {Quantities} from '../../utils/quantities' +import {SwapOrderCalculation} from '../../../translators/reactjs/state/state' +import {getQuantityWithSlippage} from '../amounts/getQuantityWithSlippage' +import {getLiquidityProviderFee} from '../costs/getLiquidityProviderFee' +import {getFrontendFee} from '../costs/getFrontendFee' +import {getMarketPrice} from '../../prices/getMarketPrice' +import {getBuyAmount} from '../amounts/getBuyAmount' +import {getSellAmount} from '../amounts/getSellAmount' +import {asQuantity} from '../../../utils/asQuantity' +import {Quantities} from '../../../utils/quantities' export const makeOrderCalculations = ({ orderType, diff --git a/packages/swap/src/helpers/orders/makePossibleMarketOrder.test.ts b/packages/swap/src/helpers/orders/factories/makePossibleMarketOrder.test.ts similarity index 98% rename from packages/swap/src/helpers/orders/makePossibleMarketOrder.test.ts rename to packages/swap/src/helpers/orders/factories/makePossibleMarketOrder.test.ts index 3146240bf9..849f789b43 100644 --- a/packages/swap/src/helpers/orders/makePossibleMarketOrder.test.ts +++ b/packages/swap/src/helpers/orders/factories/makePossibleMarketOrder.test.ts @@ -19,7 +19,6 @@ describe('makePossibleMarketOrder', () => { ptPriceTokenB: '0', fee: '0.3', provider: 'minswap', - price: 2, batcherFee: {quantity: '1', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', @@ -35,7 +34,6 @@ describe('makePossibleMarketOrder', () => { ptPriceTokenB: '0', fee: '0.3', provider: 'sundaeswap', - price: 2, batcherFee: {quantity: '10', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', diff --git a/packages/swap/src/helpers/orders/makePossibleMarketOrder.ts b/packages/swap/src/helpers/orders/factories/makePossibleMarketOrder.ts similarity index 92% rename from packages/swap/src/helpers/orders/makePossibleMarketOrder.ts rename to packages/swap/src/helpers/orders/factories/makePossibleMarketOrder.ts index 24c659212b..e5dccb5e4a 100644 --- a/packages/swap/src/helpers/orders/makePossibleMarketOrder.ts +++ b/packages/swap/src/helpers/orders/factories/makePossibleMarketOrder.ts @@ -1,7 +1,7 @@ import {Balance, Swap} from '@yoroi/types' -import {getBuyAmount} from './getBuyAmount' -import {getQuantityWithSlippage} from './getQuantityWithSlippage' +import {getBuyAmount} from '../amounts/getBuyAmount' +import {getQuantityWithSlippage} from '../amounts/getQuantityWithSlippage' /** * Create a possible market order choosing the best pool based on the given parameters. diff --git a/packages/swap/src/helpers/pools/getBestBuyPool.test.ts b/packages/swap/src/helpers/pools/getBestBuyPool.test.ts index 525c6b802e..05a2aecce2 100644 --- a/packages/swap/src/helpers/pools/getBestBuyPool.test.ts +++ b/packages/swap/src/helpers/pools/getBestBuyPool.test.ts @@ -1,7 +1,7 @@ import {Balance} from '@yoroi/types' import {getBestBuyPool} from './getBestBuyPool' -import {getBuyAmount} from '../orders/getBuyAmount' +import {getBuyAmount} from '../orders/amounts/getBuyAmount' import {mocks} from '../mocks' describe('getBestBuyPool', () => { diff --git a/packages/swap/src/helpers/pools/getBestBuyPool.ts b/packages/swap/src/helpers/pools/getBestBuyPool.ts index 56a70f66c7..082834c1e2 100644 --- a/packages/swap/src/helpers/pools/getBestBuyPool.ts +++ b/packages/swap/src/helpers/pools/getBestBuyPool.ts @@ -1,8 +1,8 @@ import {Balance, Swap} from '@yoroi/types' import {Quantities} from '../../utils/quantities' -import {getBuyAmount} from '../orders/getBuyAmount' -import {getPriceAfterFee} from '../orders/getPriceAfterFee' +import {getBuyAmount} from '../orders/amounts/getBuyAmount' +import {getPriceAfterFee} from '../prices/getPriceAfterFee' import BigNumber from 'bignumber.js' /** diff --git a/packages/swap/src/helpers/pools/getBestSellPool.test.ts b/packages/swap/src/helpers/pools/getBestSellPool.test.ts index 2b636e5b59..0c6a599ca2 100644 --- a/packages/swap/src/helpers/pools/getBestSellPool.test.ts +++ b/packages/swap/src/helpers/pools/getBestSellPool.test.ts @@ -1,7 +1,7 @@ import {Balance} from '@yoroi/types' import {getBestSellPool} from './getBestSellPool' -import {getSellAmount} from '../orders/getSellAmount' +import {getSellAmount} from '../orders/amounts/getSellAmount' import {mocks} from '../mocks' describe('getBestSellPool', () => { diff --git a/packages/swap/src/helpers/pools/getBestSellPool.ts b/packages/swap/src/helpers/pools/getBestSellPool.ts index 83c6922bd4..747e489332 100644 --- a/packages/swap/src/helpers/pools/getBestSellPool.ts +++ b/packages/swap/src/helpers/pools/getBestSellPool.ts @@ -2,8 +2,8 @@ import {Balance, Swap} from '@yoroi/types' import {Quantities} from '../../utils/quantities' import BigNumber from 'bignumber.js' -import {getPriceAfterFee} from '../orders/getPriceAfterFee' -import {getSellAmount} from '../orders/getSellAmount' +import {getPriceAfterFee} from '../prices/getPriceAfterFee' +import {getSellAmount} from '../orders/amounts/getSellAmount' /** * Find the best pool to sell based on the desired sell amount in a liquidity pool. diff --git a/packages/swap/src/helpers/orders/getMarketPrice.test.ts b/packages/swap/src/helpers/prices/getMarketPrice.test.ts similarity index 100% rename from packages/swap/src/helpers/orders/getMarketPrice.test.ts rename to packages/swap/src/helpers/prices/getMarketPrice.test.ts diff --git a/packages/swap/src/helpers/orders/getMarketPrice.ts b/packages/swap/src/helpers/prices/getMarketPrice.ts similarity index 100% rename from packages/swap/src/helpers/orders/getMarketPrice.ts rename to packages/swap/src/helpers/prices/getMarketPrice.ts diff --git a/packages/swap/src/helpers/prices/getPairPriceInPtTerms.test.ts b/packages/swap/src/helpers/prices/getPairPriceInPtTerms.test.ts new file mode 100644 index 0000000000..13ee88b0af --- /dev/null +++ b/packages/swap/src/helpers/prices/getPairPriceInPtTerms.test.ts @@ -0,0 +1,58 @@ +import {Swap} from '@yoroi/types' +import {getPairPriceInPtTerms} from './getPairPriceInPtTerms' + +describe('getPriceAfterFee', () => { + it('should calculate the correct price based on sides and decimals', () => { + // arrange + const pool: Swap.Pool = { + tokenA: {quantity: '1', tokenId: 'tokenA'}, + tokenB: {quantity: '2', tokenId: 'tokenB'}, + ptPriceTokenA: '0.03465765134', + ptPriceTokenB: '3.81247293317', + fee: '0.3', // 0.3% + provider: 'minswap', + batcherFee: {quantity: '950000', tokenId: ''}, + deposit: {quantity: '1', tokenId: ''}, + poolId: '0', + lpToken: { + quantity: '0', + tokenId: '0', + }, + } + + // act + const pricesAB = getPairPriceInPtTerms({ + amountA: pool.tokenA, + decimalsA: 6, + decimalsB: 0, + ptPriceTokenA: '1', + ptPriceTokenB: '8566.52826101672', + sell: { + quantity: '1', + tokenId: 'tokenA', + }, + }) + + const pricesBA = getPairPriceInPtTerms({ + amountA: pool.tokenA, + decimalsA: 6, + decimalsB: 0, + ptPriceTokenA: '1', + ptPriceTokenB: '8566.52826101672', + sell: { + quantity: '1', + tokenId: 'tokenB', + }, + }) + + // assert + expect(pricesAB).toStrictEqual({ + ptPriceAB: '0.008566', + ptPriceBA: '116.733403', + }) + expect(pricesBA).toStrictEqual({ + ptPriceAB: '116.733403', + ptPriceBA: '0.008566', + }) + }) +}) diff --git a/packages/swap/src/helpers/prices/getPairPriceInPtTerms.ts b/packages/swap/src/helpers/prices/getPairPriceInPtTerms.ts new file mode 100644 index 0000000000..c8969e69b4 --- /dev/null +++ b/packages/swap/src/helpers/prices/getPairPriceInPtTerms.ts @@ -0,0 +1,49 @@ +import {Balance} from '@yoroi/types' +import {BigNumber} from 'bignumber.js' +export const getPairPriceInPtTerms = ({ + sell, + amountA, + decimalsA = 0, + decimalsB = 0, + // prices not scaled - visual + ptPriceTokenA, + ptPriceTokenB, + precision, +}: { + sell: Balance.Amount + amountA: Balance.Amount + decimalsA: number + decimalsB: number + ptPriceTokenA: string + ptPriceTokenB: string + precision?: number +}) => { + const calculatePrice = ( + dividend: BigNumber, + divisor: BigNumber, + scale: number, + ) => { + return divisor.isZero() + ? '0' + : dividend + .dividedBy(divisor) + .toFixed(precision ?? scale, BigNumber.ROUND_DOWN) + } + + const scaleA = new BigNumber(10).pow(decimalsA) + const scaleB = new BigNumber(10).pow(decimalsB) + + const isSellTokenA = amountA.tokenId === sell.tokenId + const priceA = new BigNumber(ptPriceTokenA).multipliedBy(scaleA) + const priceB = new BigNumber(ptPriceTokenB).multipliedBy(scaleB) + + const ptPriceAB = isSellTokenA + ? calculatePrice(priceB, priceA, Math.max(decimalsA, decimalsB)) + : calculatePrice(priceA, priceB, Math.max(decimalsA, decimalsB)) + + const ptPriceBA = isSellTokenA + ? calculatePrice(priceA, priceB, Math.max(decimalsA, decimalsB)) + : calculatePrice(priceB, priceA, Math.max(decimalsA, decimalsB)) + + return {ptPriceAB, ptPriceBA} +} diff --git a/packages/swap/src/helpers/orders/getPriceAfterFee.test.ts b/packages/swap/src/helpers/prices/getPriceAfterFee.test.ts similarity index 98% rename from packages/swap/src/helpers/orders/getPriceAfterFee.test.ts rename to packages/swap/src/helpers/prices/getPriceAfterFee.test.ts index 44e24ab60f..85c2ac6b52 100644 --- a/packages/swap/src/helpers/orders/getPriceAfterFee.test.ts +++ b/packages/swap/src/helpers/prices/getPriceAfterFee.test.ts @@ -11,7 +11,6 @@ describe('getPriceAfterFee', () => { ptPriceTokenB: '3.81247293317', fee: '0.3', // 0.3% provider: 'minswap', - price: 2, batcherFee: {quantity: '950000', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', @@ -36,7 +35,6 @@ describe('getPriceAfterFee', () => { ptPriceTokenB: '1', fee: '0.3', // 0.3% provider: 'minswap', - price: 2, batcherFee: {quantity: '1900000', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', @@ -61,7 +59,6 @@ describe('getPriceAfterFee', () => { ptPriceTokenB: '1', fee: '0.3', // 0.3% provider: 'minswap', - price: 2, batcherFee: {quantity: '1900000', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', @@ -86,7 +83,6 @@ describe('getPriceAfterFee', () => { ptPriceTokenB: '1', fee: '0.3', // 0.3% provider: 'minswap', - price: 2, batcherFee: {quantity: '1900000', tokenId: ''}, deposit: {quantity: '1', tokenId: ''}, poolId: '0', diff --git a/packages/swap/src/helpers/orders/getPriceAfterFee.ts b/packages/swap/src/helpers/prices/getPriceAfterFee.ts similarity index 100% rename from packages/swap/src/helpers/orders/getPriceAfterFee.ts rename to packages/swap/src/helpers/prices/getPriceAfterFee.ts diff --git a/packages/swap/src/helpers/transformers.ts b/packages/swap/src/helpers/transformers.ts index 960dbe64bb..9626bd3224 100644 --- a/packages/swap/src/helpers/transformers.ts +++ b/packages/swap/src/helpers/transformers.ts @@ -150,7 +150,6 @@ export const transformersMaker = ( lpToken: asYoroiAmount(lpToken), batcherFee: asYoroiAmount({amount: batcherFee, address: undefined}), fee: poolFee, - price: 0, poolId, provider, } diff --git a/packages/swap/src/index.ts b/packages/swap/src/index.ts index e75a57dcec..91d86d1005 100644 --- a/packages/swap/src/index.ts +++ b/packages/swap/src/index.ts @@ -1,7 +1,4 @@ -export { - makeStorageMaker, - makeStorageMakerDefault, -} from './adapters/async-storage/storage.mocks' +// mocks export { mockSwapManager, mockSwapManagerDefault, @@ -10,16 +7,31 @@ export { export {mockSwapStateDefault} from './translators/reactjs/state/state.mocks' export {apiMocks} from './adapters/openswap-api/api.mocks' -export {getBuyAmount} from './helpers/orders/getBuyAmount' -export {getSellAmount} from './helpers/orders/getSellAmount' -export {makePossibleMarketOrder} from './helpers/orders/makePossibleMarketOrder' -export {getMarketPrice} from './helpers/orders/getMarketPrice' -export {getMinAdaReceiveAfterSlippage} from './helpers/orders/getMinAdaReceiveAfterSlippage' -export {getLiquidityProviderFee} from './helpers/orders/getLiquidityProviderFee' -export {makeLimitOrder} from './helpers/orders/makeLimitOrder' +// orders amounts +export {getBuyAmount} from './helpers/orders/amounts/getBuyAmount' +export {getSellAmount} from './helpers/orders/amounts/getSellAmount' +export {getMinAdaReceiveAfterSlippage} from './helpers/orders/amounts/getMinAdaReceiveAfterSlippage' +export {getQuantityWithSlippage} from './helpers/orders/amounts/getQuantityWithSlippage' +// orders factories +export {makePossibleMarketOrder} from './helpers/orders/factories/makePossibleMarketOrder' +export {makeLimitOrder} from './helpers/orders/factories/makeLimitOrder' +export {makeOrderCalculations} from './helpers/orders/factories/makeOrderCalculations' +// orders costs +export {getLiquidityProviderFee} from './helpers/orders/costs/getLiquidityProviderFee' +export {getFrontendFee} from './helpers/orders/costs/getFrontendFee' + +// prices +export {getMarketPrice} from './helpers/prices/getMarketPrice' +export {getPriceAfterFee} from './helpers/prices/getPriceAfterFee' +export {getPairPriceInPtTerms} from './helpers/prices/getPairPriceInPtTerms' +// pools export {getPoolUrlByProvider} from './helpers/pools/getPoolUrlByProvider' +export {getBestBuyPool} from './helpers/pools/getBestBuyPool' +export {getBestSellPool} from './helpers/pools/getBestSellPool' +export {getBestPoolCalculation} from './helpers/pools/getBestPoolCalculation' +// translators export {SwapProvider} from './translators/reactjs/provider/SwapProvider' export {SwapState} from './translators/reactjs/state/state' export {useSwapCreateOrder} from './translators/reactjs/hooks/useSwapCreateOrder' @@ -29,19 +41,21 @@ export {useSwapPoolsByPair} from './translators/reactjs/hooks/useSwapPoolsByPair export {useSwapSetSlippage} from './translators/reactjs/hooks/useSwapSetSlippage' export {useSwapSlippage} from './translators/reactjs/hooks/useSwapSlippage' export {useSwapTokensByPairToken} from './translators/reactjs/hooks/useSwapTokensByPairToken' +export {useSwap} from './translators/reactjs/hooks/useSwap' +export { + supportedProviders, + milkHoldersDiscountTiers, + milkTokenId, +} from './translators/constants' +// factories export {swapApiMaker} from './adapters/openswap-api/api' export {swapManagerMaker} from './manager' - -export {useSwap} from './translators/reactjs/hooks/useSwap' - export { swapStorageMaker, swapStorageSlippageKey, } from './adapters/async-storage/storage' - export { - supportedProviders, - milkHoldersDiscountTiers, - milkTokenId, -} from './translators/constants' + makeStorageMaker, + makeStorageMakerDefault, +} from './adapters/async-storage/storage.mocks' diff --git a/packages/swap/src/translators/reactjs/state/state.ts b/packages/swap/src/translators/reactjs/state/state.ts index d3e3e5191c..b97a604534 100644 --- a/packages/swap/src/translators/reactjs/state/state.ts +++ b/packages/swap/src/translators/reactjs/state/state.ts @@ -3,7 +3,7 @@ import {produce} from 'immer' import {Quantities} from '../../../utils/quantities' import {SwapDiscountTier} from '../../../translators/constants' -import {makeOrderCalculations} from '../../../helpers/orders/makeOrderCalculations' +import {makeOrderCalculations} from '../../../helpers/orders/factories/makeOrderCalculations' import {selectedPoolCalculationSelector} from './selectors/selectedPoolCalculationSelector' import {getBestPoolCalculation} from '../../../helpers/pools/getBestPoolCalculation' diff --git a/packages/types/src/swap/pool.ts b/packages/types/src/swap/pool.ts index bf34c0c970..27e4476e48 100644 --- a/packages/types/src/swap/pool.ts +++ b/packages/types/src/swap/pool.ts @@ -29,7 +29,6 @@ export type SwapPool = { tokenB: BalanceAmount ptPriceTokenA: string // float, current price in lovelace of tokenA, i.e. 0.000000000000000000. ptPriceTokenB: string // float, current price in lovelace of tokenB, i.e. 0.000000000000000000. - price: number // float, current price in tokenA / tokenB according to the pool, NOT SUITABLE for price calculations, just for display purposes, i.e. 0.9097362621640215. batcherFee: BalanceAmount deposit: BalanceAmount // amount of deposit / minUTxO required by protocol, returned to user, in lovelace. // utxo: string // txhash#txindex of latest transaction involving this pool. From d26247ab350f72dc49df299efd63fb0e699039d1 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 19:38:57 +0100 Subject: [PATCH 35/67] chore: state and behaviors --- .../SelectPoolFromList/SelectPoolFromList.tsx | 38 ++++++++-------- .../CreateOrder/CreateOrder.tsx | 2 +- .../EditBuyAmount/EditBuyAmount.tsx | 14 ++---- .../SelectBuyTokenFromListScreen.tsx | 15 +++++-- .../SelectSellTokenFromListScreen.tsx | 12 +++-- .../orders/factories/makeOrderCalculations.ts | 45 +++++++++++-------- 6 files changed, 69 insertions(+), 57 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx index 761f768943..47221c5c15 100644 --- a/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx +++ b/apps/wallet-mobile/src/features/Swap/common/SelectPool/SelectPoolFromList/SelectPoolFromList.tsx @@ -1,6 +1,5 @@ -import {useSwap} from '@yoroi/swap' +import {getPairPriceInPtTerms, useSwap} from '@yoroi/swap' import {Balance, Swap} from '@yoroi/types' -import BigNumber from 'bignumber.js' import React, {useState} from 'react' import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' import LinearGradient from 'react-native-linear-gradient' @@ -29,7 +28,7 @@ export const SelectPoolFromList = ({pools = []}: Props) => { const navigate = useNavigateTo() const {track} = useMetrics() - const handleCardSelect = (pool: Swap.Pool) => { + const handleOnPoolSelection = (pool: Swap.Pool) => { track.swapPoolChanged() selectedPoolChanged(pool.poolId) setSelectedCardIndex(pool.poolId) @@ -57,7 +56,7 @@ export const SelectPoolFromList = ({pools = []}: Props) => { colors={pool.poolId === selectedCardIndex ? ['#E4E8F7', '#C6F7F7'] : [COLORS.WHITE, COLORS.WHITE]} style={styles.linearGradient} > - handleCardSelect(pool)} style={[styles.card]}> + handleOnPoolSelection(pool)} style={[styles.card]}> @@ -120,26 +119,25 @@ export const SelectPoolFromList = ({pools = []}: Props) => { type PriceInAdaProps = {pool: Swap.Pool; wallet: YoroiWallet; sell: Balance.Amount} const PriceInAda = ({pool, wallet, sell}: PriceInAdaProps) => { const strings = useStrings() - - const {decimals: decimalsA = 0}= useTokenInfo({wallet, tokenId: pool.tokenA.tokenId}) - const {decimals: decimalsB = 0}= useTokenInfo({wallet, tokenId: pool.tokenB.tokenId}) - - const scaleA = new BigNumber(10).pow(decimalsA) - const scaleB = new BigNumber(10).pow(decimalsB) - - const isSellTokenA = pool.tokenA.tokenId === sell.tokenId - const [dividend, divisor] = isSellTokenA - ? [new BigNumber(pool.ptPriceTokenB).multipliedBy(scaleB), new BigNumber(pool.ptPriceTokenA).multipliedBy(scaleA)] - : [new BigNumber(pool.ptPriceTokenA).multipliedBy(scaleA), new BigNumber(pool.ptPriceTokenB).multipliedBy(scaleB)] - // limit decimals - const ptPrice = divisor.isZero() ? '0' : dividend.dividedBy(divisor).toFixed(Math.max(decimalsA, decimalsB), BigNumber.ROUND_DOWN) - // const price = parsedPrice != null ? asQuantity(parsedPrice) : Quantities.zero - // const formattedPriceInPt = `${Quantities.format(price, 0, decimals)} ${ticker}` + const {ptPriceTokenA, ptPriceTokenB, tokenA, tokenB} = pool + + const {decimals: decimalsA = 0} = useTokenInfo({wallet, tokenId: tokenA.tokenId}) + const {decimals: decimalsB = 0} = useTokenInfo({wallet, tokenId: tokenB.tokenId}) + + const {ptPriceAB} = getPairPriceInPtTerms({ + amountA: tokenA, + decimalsA, + decimalsB, + ptPriceTokenA, + ptPriceTokenB, + sell, + }) + return ( {strings.price} - {ptPrice} + {ptPriceAB} ) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx index 7b460e6e0b..18e4c710db 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/CreateOrder.tsx @@ -42,7 +42,7 @@ export const CreateOrder = () => { tokenB: orderData.amounts.buy.tokenId, }, { - enabled: isBuyTouched, + enabled: isBuyTouched && isSellTouched, onSuccess: (pools) => { poolPairsChanged(pools) }, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx index c4fb2b03dd..ffc6414794 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx @@ -20,7 +20,7 @@ export const EditBuyAmount = () => { const inputRef = React.useRef(null) const {orderData, buyQuantityChanged} = useSwap() - const {isBuyTouched} = useSwapTouched() + const {isBuyTouched, isSellTouched} = useSwapTouched() const pool = orderData.selectedPoolCalculation?.pool const {tokenId, quantity} = orderData.amounts.buy const tokenInfo = useTokenInfo({wallet, tokenId}) @@ -30,15 +30,6 @@ export const EditBuyAmount = () => { const [inputValue, setInputValue] = React.useState(Quantities.format(quantity, tokenInfo.decimals ?? 0)) React.useEffect(() => { - console.log('EditBuyAmount::useEffect') - console.log( - 'isBuyTouched', - isBuyTouched, - 'inputRef?.current?.isFocused()', - inputRef?.current?.isFocused(), - 'quantity', - quantity, - ) if (isBuyTouched && !inputRef?.current?.isFocused()) { setInputValue(Quantities.format(quantity, tokenInfo.decimals ?? 0)) } @@ -46,7 +37,8 @@ export const EditBuyAmount = () => { const poolSupply = tokenId === pool?.tokenA.tokenId ? pool?.tokenA.quantity : pool?.tokenB.quantity const hasSupply = !Quantities.isGreaterThan(quantity, poolSupply ?? Quantities.zero) - const showError = (!Quantities.isZero(quantity) && !hasSupply) || (isBuyTouched && pool === undefined) + const showError = + (!Quantities.isZero(quantity) && !hasSupply) || (isSellTouched && isBuyTouched && pool === undefined) const onChangeQuantity = (text: string) => { try { diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 8588dcc76e..6ba130870f 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -178,13 +178,15 @@ const TokenList = () => { type SelectableTokenProps = {disabled?: boolean; tokenForList: TokenForList; wallet: YoroiWallet} const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {buyTokenIdChanged} = useSwap() - const {buyTouched} = useSwapTouched() + const {buyTokenIdChanged, orderData} = useSwap() + const {buyTouched, isSellTouched} = useSwapTouched() const navigateTo = useNavigateTo() const balanceAvailable = useBalance({wallet, tokenId: tokenForList.id}) const {track} = useMetrics() - const onSelect = () => { + const isDisabled = tokenForList.id === orderData.amounts.sell.tokenId && isSellTouched + + const handleOnTokenSelection = () => { track.swapAssetToChanged({ to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], }) @@ -195,7 +197,12 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { } return ( - + { type SelectableTokenProps = {disabled?: boolean; tokenInfo: Balance.TokenInfo; wallet: YoroiWallet} const SelectableToken = ({tokenInfo, wallet}: SelectableTokenProps) => { const {closeSearch} = useSearch() - const {sellTokenIdChanged} = useSwap() + const {sellTokenIdChanged, orderData} = useSwap() const {sellTouched} = useSwapTouched() const navigateTo = useNavigateTo() const {track} = useMetrics() const balanceAvailable = useBalance({wallet, tokenId: tokenInfo.id}) + const isDisabled = tokenInfo.id === orderData.amounts.buy.tokenId - const onSelect = () => { + const handleOnTokenSelection = () => { track.swapAssetFromChanged({ from_asset: [{asset_name: tokenInfo.name, asset_ticker: tokenInfo.ticker, policy_id: tokenInfo.group}], }) @@ -101,7 +102,12 @@ const SelectableToken = ({tokenInfo, wallet}: SelectableTokenProps) => { } return ( - + ) diff --git a/packages/swap/src/helpers/orders/factories/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/factories/makeOrderCalculations.ts index 1e38b5d8a2..204c17e2b8 100644 --- a/packages/swap/src/helpers/orders/factories/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/factories/makeOrderCalculations.ts @@ -67,10 +67,11 @@ export const makeOrderCalculations = ({ const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) const [ptPriceBuy, ptPriceSell] = isBuyTokenA - ? [pool.ptPriceTokenA, pool.ptPriceTokenB] - : [pool.ptPriceTokenB, pool.ptPriceTokenA] + ? [new BigNumber(pool.ptPriceTokenA), new BigNumber(pool.ptPriceTokenB)] + : [new BigNumber(pool.ptPriceTokenB), new BigNumber(pool.ptPriceTokenA)] // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) + // TODO: it needs update, prices by muesli are provided in ADA, quantities in atomic units const frontendFeeInfo = getFrontendFee({ sell, buy, @@ -78,31 +79,39 @@ export const makeOrderCalculations = ({ primaryTokenId, sellInPrimaryTokenValue: { tokenId: primaryTokenId, - quantity: asQuantity( - new BigNumber(amounts.sell.quantity) - .dividedBy(ptPriceSell) - .integerValue(BigNumber.ROUND_CEIL), - ), + quantity: ptPriceSell.isZero() + ? Quantities.zero + : asQuantity( + new BigNumber(amounts.sell.quantity) + .dividedBy(ptPriceSell) + .integerValue(BigNumber.ROUND_CEIL), + ), }, buyInPrimaryTokenValue: { tokenId: primaryTokenId, - quantity: asQuantity( - new BigNumber(amounts.buy.quantity) - .dividedBy(ptPriceBuy) - .integerValue(BigNumber.ROUND_CEIL), - ), + quantity: ptPriceBuy.isZero() + ? Quantities.zero + : asQuantity( + new BigNumber(amounts.buy.quantity) + .dividedBy(ptPriceBuy) + .integerValue(BigNumber.ROUND_CEIL), + ), }, }) // transform fees in terms of sell side quantity * pt price (unit of fees) // it applies market price always const feeInSellSideQuantities = { - batcherFee: new BigNumber(pool.batcherFee.quantity) - .dividedBy(ptPriceSell) - .integerValue(BigNumber.ROUND_CEIL), - frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .dividedBy(ptPriceSell) - .integerValue(BigNumber.ROUND_CEIL), + batcherFee: ptPriceSell.isZero() + ? Quantities.zero + : new BigNumber(pool.batcherFee.quantity) + .dividedBy(ptPriceSell) + .integerValue(BigNumber.ROUND_CEIL), + frontendFee: ptPriceSell.isZero() + ? Quantities.zero + : new BigNumber(frontendFeeInfo.fee.quantity) + .dividedBy(ptPriceSell) + .integerValue(BigNumber.ROUND_CEIL), } const priceWithSlippage = Quantities.isZero(buyAmountWithSlippage.quantity) From 0580f4d8418345112d9fd8fb7275cd79260653a0 Mon Sep 17 00:00:00 2001 From: Ruslan Dudin Date: Tue, 10 Oct 2023 12:57:14 +0300 Subject: [PATCH 36/67] New Crowdin updates (#2747) --- apps/wallet-mobile/src/i18n/locales/bn-BD.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/cs-CZ.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/de-DE.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/el-GR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/fil-PH.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/fr-FR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/hr-HR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/hu-HU.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/id-ID.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/it-IT.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/ja-JP.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/ko-KR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/nl-NL.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/pl-PL.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/pt-BR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/ru-RU.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sk-SK.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sl-SI.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sv-SE.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sw-KE.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/tr-TR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/uk-UA.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/vi-VN.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/zh-Hans.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/zh-Hant.json | 6 ++++-- 25 files changed, 100 insertions(+), 50 deletions(-) diff --git a/apps/wallet-mobile/src/i18n/locales/bn-BD.json b/apps/wallet-mobile/src/i18n/locales/bn-BD.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/bn-BD.json +++ b/apps/wallet-mobile/src/i18n/locales/bn-BD.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/cs-CZ.json b/apps/wallet-mobile/src/i18n/locales/cs-CZ.json index 00bdf73fb2..32749fa7f8 100644 --- a/apps/wallet-mobile/src/i18n/locales/cs-CZ.json +++ b/apps/wallet-mobile/src/i18n/locales/cs-CZ.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/de-DE.json b/apps/wallet-mobile/src/i18n/locales/de-DE.json index 586a65f2aa..bdb1c503a1 100644 --- a/apps/wallet-mobile/src/i18n/locales/de-DE.json +++ b/apps/wallet-mobile/src/i18n/locales/de-DE.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/el-GR.json b/apps/wallet-mobile/src/i18n/locales/el-GR.json index 1ee34cdd35..ed0b3f1de2 100644 --- a/apps/wallet-mobile/src/i18n/locales/el-GR.json +++ b/apps/wallet-mobile/src/i18n/locales/el-GR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/fil-PH.json b/apps/wallet-mobile/src/i18n/locales/fil-PH.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/fil-PH.json +++ b/apps/wallet-mobile/src/i18n/locales/fil-PH.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/fr-FR.json b/apps/wallet-mobile/src/i18n/locales/fr-FR.json index d06349396c..a68ac857af 100644 --- a/apps/wallet-mobile/src/i18n/locales/fr-FR.json +++ b/apps/wallet-mobile/src/i18n/locales/fr-FR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "auto", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": "Valeur totale verrouillée", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "Ordres complétés", "swap.listOrders.open": "Ordres en cours", "swap.listOrders.sheet.title": "Confirmer l'annulation de l'ordre", diff --git a/apps/wallet-mobile/src/i18n/locales/hr-HR.json b/apps/wallet-mobile/src/i18n/locales/hr-HR.json index f78273303a..d281577526 100644 --- a/apps/wallet-mobile/src/i18n/locales/hr-HR.json +++ b/apps/wallet-mobile/src/i18n/locales/hr-HR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/hu-HU.json b/apps/wallet-mobile/src/i18n/locales/hu-HU.json index efb4c99cf6..e8993bce85 100644 --- a/apps/wallet-mobile/src/i18n/locales/hu-HU.json +++ b/apps/wallet-mobile/src/i18n/locales/hu-HU.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/id-ID.json b/apps/wallet-mobile/src/i18n/locales/id-ID.json index 21c5e54500..26602664c1 100644 --- a/apps/wallet-mobile/src/i18n/locales/id-ID.json +++ b/apps/wallet-mobile/src/i18n/locales/id-ID.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/it-IT.json b/apps/wallet-mobile/src/i18n/locales/it-IT.json index cc138280ec..c6eb4c94f3 100644 --- a/apps/wallet-mobile/src/i18n/locales/it-IT.json +++ b/apps/wallet-mobile/src/i18n/locales/it-IT.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/ja-JP.json b/apps/wallet-mobile/src/i18n/locales/ja-JP.json index ebc33e9621..a5505a7232 100644 --- a/apps/wallet-mobile/src/i18n/locales/ja-JP.json +++ b/apps/wallet-mobile/src/i18n/locales/ja-JP.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/ko-KR.json b/apps/wallet-mobile/src/i18n/locales/ko-KR.json index 1cc2fd9656..afebaf2d5e 100644 --- a/apps/wallet-mobile/src/i18n/locales/ko-KR.json +++ b/apps/wallet-mobile/src/i18n/locales/ko-KR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/nl-NL.json b/apps/wallet-mobile/src/i18n/locales/nl-NL.json index b2847e097c..2b3840d78a 100644 --- a/apps/wallet-mobile/src/i18n/locales/nl-NL.json +++ b/apps/wallet-mobile/src/i18n/locales/nl-NL.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/pl-PL.json b/apps/wallet-mobile/src/i18n/locales/pl-PL.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/pl-PL.json +++ b/apps/wallet-mobile/src/i18n/locales/pl-PL.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/pt-BR.json b/apps/wallet-mobile/src/i18n/locales/pt-BR.json index 0351dc5bc4..5304d656da 100644 --- a/apps/wallet-mobile/src/i18n/locales/pt-BR.json +++ b/apps/wallet-mobile/src/i18n/locales/pt-BR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Mínimo", - "swap.swapScreen.swapFees": "As taxas da operação incluem:\n • Taxa do executor das ordens\n • Taxa da carteira\n • Taxa do operador da reserva", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Mín. a ser recebido", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": "VTA", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/ru-RU.json b/apps/wallet-mobile/src/i18n/locales/ru-RU.json index dda3deaad3..1c48e28b1d 100644 --- a/apps/wallet-mobile/src/i18n/locales/ru-RU.json +++ b/apps/wallet-mobile/src/i18n/locales/ru-RU.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(авто)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sk-SK.json b/apps/wallet-mobile/src/i18n/locales/sk-SK.json index 61d9f17618..d98854a9bb 100644 --- a/apps/wallet-mobile/src/i18n/locales/sk-SK.json +++ b/apps/wallet-mobile/src/i18n/locales/sk-SK.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sl-SI.json b/apps/wallet-mobile/src/i18n/locales/sl-SI.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/sl-SI.json +++ b/apps/wallet-mobile/src/i18n/locales/sl-SI.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sv-SE.json b/apps/wallet-mobile/src/i18n/locales/sv-SE.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/sv-SE.json +++ b/apps/wallet-mobile/src/i18n/locales/sv-SE.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sw-KE.json b/apps/wallet-mobile/src/i18n/locales/sw-KE.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/sw-KE.json +++ b/apps/wallet-mobile/src/i18n/locales/sw-KE.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/tr-TR.json b/apps/wallet-mobile/src/i18n/locales/tr-TR.json index 1acda6a62c..fe47afa2a7 100644 --- a/apps/wallet-mobile/src/i18n/locales/tr-TR.json +++ b/apps/wallet-mobile/src/i18n/locales/tr-TR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/uk-UA.json b/apps/wallet-mobile/src/i18n/locales/uk-UA.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/uk-UA.json +++ b/apps/wallet-mobile/src/i18n/locales/uk-UA.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/vi-VN.json b/apps/wallet-mobile/src/i18n/locales/vi-VN.json index aaf22662b0..0fd161995b 100644 --- a/apps/wallet-mobile/src/i18n/locales/vi-VN.json +++ b/apps/wallet-mobile/src/i18n/locales/vi-VN.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/zh-Hans.json b/apps/wallet-mobile/src/i18n/locales/zh-Hans.json index b453229383..fcacf61595 100644 --- a/apps/wallet-mobile/src/i18n/locales/zh-Hans.json +++ b/apps/wallet-mobile/src/i18n/locales/zh-Hans.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/zh-Hant.json b/apps/wallet-mobile/src/i18n/locales/zh-Hant.json index cb8208a273..410f67bafa 100644 --- a/apps/wallet-mobile/src/i18n/locales/zh-Hant.json +++ b/apps/wallet-mobile/src/i18n/locales/zh-Hant.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", From 9c3511e2f95b4d4b3587812b4668ad360b1e91db Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Tue, 10 Oct 2023 13:05:48 +0200 Subject: [PATCH 37/67] Min received with slippage --- .../ConfirmTxScreen/TransactionSummary.tsx | 10 ++---- .../CreateOrder/EditPool/ShowPoolActions.tsx | 10 ++---- .../getMinAdaReceiveAfterSlippage.test.ts | 34 ------------------- .../amounts/getMinAdaReceiveAfterSlippage.ts | 30 ---------------- packages/swap/src/index.ts | 1 - 5 files changed, 6 insertions(+), 79 deletions(-) delete mode 100644 packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts delete mode 100644 packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx index 8200a426d9..04612bbb6f 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx @@ -1,11 +1,10 @@ -import {getMinAdaReceiveAfterSlippage, useSwap} from '@yoroi/swap' +import {useSwap} from '@yoroi/swap' import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {Icon, Spacer, Text} from '../../../../components' import {AmountItem} from '../../../../components/AmountItem/AmountItem' import {BottomSheetModal} from '../../../../components/BottomSheetModal' -import {useLanguage} from '../../../../i18n' import {useSelectedWallet} from '../../../../SelectedWallet' import {COLORS} from '../../../../theme' import {useTokenInfo} from '../../../../yoroi-wallets/hooks' @@ -20,7 +19,6 @@ export const TransactionSummary = () => { }) const strings = useStrings() const wallet = useSelectedWallet() - const {numberLocale} = useLanguage() const {orderData} = useSwap() const {amounts, selectedPoolCalculation} = orderData @@ -39,11 +37,9 @@ export const TransactionSummary = () => { }, { label: strings.swapMinReceivedTitle, - value: `${getMinAdaReceiveAfterSlippage( - amounts.buy.quantity, - orderData.slippage, + value: `${Quantities.format( + selectedPoolCalculation?.buyAmountWithSlippage?.quantity ?? Quantities.zero, buyTokenInfo.decimals ?? 0, - numberLocale, )} ${tokenToBuyName}`, info: strings.swapMinReceived, }, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx index 9a15564560..ddc9f35c62 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx @@ -1,4 +1,4 @@ -import {getMinAdaReceiveAfterSlippage, useSwap} from '@yoroi/swap' +import {useSwap} from '@yoroi/swap' import {capitalize} from 'lodash' import React from 'react' import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' @@ -10,7 +10,6 @@ import { HiddenInfoWrapper, Spacer, } from '../../../../../../components' -import {useLanguage} from '../../../../../../i18n' import {useSelectedWallet} from '../../../../../../SelectedWallet' import {COLORS} from '../../../../../../theme' import {useTokenInfo} from '../../../../../../yoroi-wallets/hooks' @@ -22,7 +21,6 @@ import {useSwapTouched} from '../../../../common/SwapFormProvider' export const ShowPoolActions = () => { const navigateTo = useNavigateTo() - const {numberLocale} = useLanguage() const {orderData} = useSwap() const strings = useStrings() const {isBuyTouched, isSellTouched, isPoolTouched} = useSwapTouched() @@ -90,11 +88,9 @@ export const ShowPoolActions = () => { selectedPoolCalculation.pool.batcherFee.quantity, Number(wallet.primaryTokenInfo.decimals), )} - minReceived={getMinAdaReceiveAfterSlippage( - amounts.buy.quantity, - orderData.slippage, + minReceived={Quantities.format( + selectedPoolCalculation.buyAmountWithSlippage.quantity, buyTokenInfo.decimals ?? 0, - numberLocale, )} minAda={Quantities.format( selectedPoolCalculation.pool.deposit.quantity, diff --git a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts deleted file mode 100644 index d0ac842251..0000000000 --- a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {mockNumberLocale} from '../../../adapters/intl/number-locale.mocks' -import {asQuantity} from '../../../utils/asQuantity' -import {getMinAdaReceiveAfterSlippage} from './getMinAdaReceiveAfterSlippage' - -describe('getMinAdaReceiveAfterSlippage', () => { - it('should calculate the correct minimum ADA received after applying slippage', () => { - expect( - getMinAdaReceiveAfterSlippage( - asQuantity(1000), - 0.03, - 2, - mockNumberLocale, - ), - ).toBe('9.9') - expect( - getMinAdaReceiveAfterSlippage(asQuantity(500), 1, 2, mockNumberLocale), - ).toBe('4.9') - expect( - getMinAdaReceiveAfterSlippage(asQuantity(1000), 2, 2, mockNumberLocale), - ).toBe('9.8') - }) - - it('should return the original amount when slippage is zero', () => { - expect( - getMinAdaReceiveAfterSlippage(asQuantity(1000), 0, 2, mockNumberLocale), - ).toBe('1') - }) - - it('should return zero when the output amount is zero', () => { - expect( - getMinAdaReceiveAfterSlippage(asQuantity(0), 5, 2, mockNumberLocale), - ).toBe('') - }) -}) diff --git a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts deleted file mode 100644 index 828abc1b15..0000000000 --- a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Balance, Numbers} from '@yoroi/types' -import {Quantities} from '../../../utils/quantities' -import {asQuantity} from '../../../utils/asQuantity' - -/** - * Calculate the minimum amount of ADA received after accounting for slippage. - * - * @param {Balance.Quantity} outputAmount - The amount of ADA or output currency. - * @param {number} slippagePercentage - The slippage percentage as a decimal (e.g., 3% as 0.03). - * @param {number} decimals - The number of decimal places for formatting the result. - * @param {NumberLocale} numberLocale - The locale information for formatting numbers. - * - * @returns {string} The minimum ADA amount received after slippage as a string with specified decimals. - */ - -export const getMinAdaReceiveAfterSlippage = ( - outputAmount: Balance.Quantity, - slippagePercentage: number, - decimals: number, - numberLocale: Numbers.Locale, -): string => { - const slippageDecimal = slippagePercentage / 100 - const result = Number(outputAmount) / (1 + slippageDecimal) - const [quantities] = Quantities.parseFromText( - Quantities.denominated(asQuantity(result), decimals), - decimals, - numberLocale, - ) - return quantities.slice(0, -1) -} diff --git a/packages/swap/src/index.ts b/packages/swap/src/index.ts index 91d86d1005..c6cb65ddcd 100644 --- a/packages/swap/src/index.ts +++ b/packages/swap/src/index.ts @@ -10,7 +10,6 @@ export {apiMocks} from './adapters/openswap-api/api.mocks' // orders amounts export {getBuyAmount} from './helpers/orders/amounts/getBuyAmount' export {getSellAmount} from './helpers/orders/amounts/getSellAmount' -export {getMinAdaReceiveAfterSlippage} from './helpers/orders/amounts/getMinAdaReceiveAfterSlippage' export {getQuantityWithSlippage} from './helpers/orders/amounts/getQuantityWithSlippage' // orders factories export {makePossibleMarketOrder} from './helpers/orders/factories/makePossibleMarketOrder' From 0ecf95c097349b69d628671abf703003a9a0d18f Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 10 Oct 2023 14:22:02 +0300 Subject: [PATCH 38/67] fix: edit limit price (#2748) --- .../CreateOrder/EditLimitPrice.tsx | 10 +++-- .../ShowTokenActions/ClearQuantities.tsx | 3 +- .../ShowTokenActions/TopTokenActions.tsx | 3 +- .../Swap/common/AmountCard/AmountCard.json | 40 +++++++++---------- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx index 53d342cf13..74ae20f445 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx @@ -19,6 +19,7 @@ export const EditLimitPrice = () => { const {numberLocale} = useLanguage() const [text, setText] = React.useState('') const wallet = useSelectedWallet() + const inputRef = React.useRef(null) const {orderData, limitPriceChanged} = useSwap() const sellTokenInfo = useTokenInfo({wallet, tokenId: orderData.amounts.sell.tokenId}) @@ -33,7 +34,8 @@ export const EditLimitPrice = () => { React.useEffect(() => { if (orderData.type === 'limit') { - setText(Quantities.format(orderData.limitPrice ?? Quantities.zero, denomination, PRECISION)) + !inputRef?.current?.isFocused() && + setText(Quantities.format(orderData.limitPrice ?? Quantities.zero, denomination, PRECISION)) } else { setText( Quantities.format(orderData.selectedPoolCalculation?.prices.market ?? Quantities.zero, denomination, PRECISION), @@ -54,7 +56,7 @@ export const EditLimitPrice = () => { {disabled ? strings.marketPrice : strings.limitPrice} - + @@ -70,8 +72,9 @@ type AmountInputProps = { value?: string onChange(value: string): void editable: boolean + inputRef?: React.RefObject } -const AmountInput = ({onChange, value, editable}: AmountInputProps) => { +const AmountInput = ({onChange, value, editable, inputRef}: AmountInputProps) => { return ( { style={styles.amountInput} underlineColorAndroid="transparent" editable={editable} + ref={inputRef} /> ) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx index 28c49f79e6..a5873c84c6 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx @@ -1,6 +1,6 @@ import {useSwap} from '@yoroi/swap' import React from 'react' -import {StyleSheet, Text} from 'react-native' +import {Keyboard, StyleSheet, Text} from 'react-native' import {TouchableOpacity} from 'react-native-gesture-handler' import {COLORS} from '../../../../../../theme' @@ -13,6 +13,7 @@ export const ClearQuantities = () => { const {poolDefaulted} = useSwapTouched() const handleReset = () => { + Keyboard.dismiss() resetQuantities() poolDefaulted() } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx index 561123cbc4..d60ef48368 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx @@ -1,6 +1,6 @@ import {useSwap, useSwapPoolsByPair} from '@yoroi/swap' import React from 'react' -import {StyleSheet, View} from 'react-native' +import {Keyboard, StyleSheet, View} from 'react-native' import {TouchableOpacity} from 'react-native-gesture-handler' import {Icon} from '../../../../../../components' @@ -40,6 +40,7 @@ export const TopTokenActions = () => { } const handleRefresh = () => { + Keyboard.dismiss() refetch() } diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index 7fa3933302..51c7130421 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Select token", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 134, + "line": 135, "column": 15, - "index": 4170 + "index": 4171 }, "end": { - "line": 137, + "line": 138, "column": 3, - "index": 4253 + "index": 4254 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!Current Balance", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 138, + "line": 139, "column": 18, - "index": 4273 + "index": 4274 }, "end": { - "line": 141, + "line": 142, "column": 3, - "index": 4362 + "index": 4363 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!Not enough balance", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 142, + "line": 143, "column": 20, - "index": 4384 + "index": 4385 }, "end": { - "line": 145, + "line": 146, "column": 3, - "index": 4478 + "index": 4479 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Not enough supply in the pool", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 146, + "line": 147, "column": 19, - "index": 4499 + "index": 4500 }, "end": { - "line": 149, + "line": 150, "column": 3, - "index": 4603 + "index": 4604 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!! This pair is not available in any liquidity pool", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 150, + "line": 151, "column": 10, - "index": 4615 + "index": 4616 }, "end": { - "line": 153, + "line": 154, "column": 3, - "index": 4730 + "index": 4731 } } ] \ No newline at end of file From f2677b65ff8e342a08110c1d104411fadd3d3cd0 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 20:59:17 +0100 Subject: [PATCH 39/67] wip: order calcs --- .../helpers/orders/makeOrderCalculations.ts | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 packages/swap/src/helpers/orders/makeOrderCalculations.ts diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts new file mode 100644 index 0000000000..46fda6cbf5 --- /dev/null +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -0,0 +1,77 @@ +import {Balance, Swap, Writable} from '@yoroi/types' +import { + SwapCreateOrderActionType, + SwapOrderCalulation, +} from '../../translators/reactjs/state/state' +import {getQuantityWithSlippage} from './getQuantityWithSlippage' +import {Quantities} from '../../utils/quantities' + +export const makeOrderCalculations = ({ + orderData, + pools, + primaryTokenId, + action, +}: Readonly<{ + orderData: Swap.CreateOrderData + pools: Array + sellAmount: Balance.Amount + buyAmount: Balance.Amount + slippage: number + primaryTokenId: Balance.TokenInfo['id'] + action: + | SwapCreateOrderActionType.SellQuantityChanged + | SwapCreateOrderActionType.SellTokenIdChanged + | SwapCreateOrderActionType.BuyQuantityChanged + | SwapCreateOrderActionType.BuyTokenIdChanged + | SwapCreateOrderActionType.SlippageChanged + | SwapCreateOrderActionType.PoolPairsChanged +}>) => { + console.log(action) + const result: Array = [] + + pools.forEach((pool) => { + let orderCalculation: Writable + + orderCalculation = { + cost: { + batcherFee: { + tokenId: primaryTokenId, + quantity: Quantities.zero, + }, + frontendFeeInfo: { + fee: { + tokenId: primaryTokenId, + quantity: Quantities.zero, + }, + tier: undefined, + }, + deposit: pool.deposit, + liquidityFee: { + tokenId: orderData.amounts.sell.tokenId, + quantity: Quantities.zero, + }, + }, + buyAmountWithSlippage: { + quantity: getQuantityWithSlippage( + orderData.amounts.buy.quantity, + orderData.slippage, + ), + tokenId: orderData.amounts.buy.tokenId, + }, + sell: { + price: '', + priceDifference: '', + priceWithFees: '', + priceWithFeesAndSlippage: '', + priceWithSlippage: '', + }, + pool, + } + + result.push(orderCalculation) + + // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? + }) + + return result +} From de0654ff761a41cbf9c36efa61c323ed4a46d5c9 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 21:40:39 +0100 Subject: [PATCH 40/67] wip: liquidity prov fee + tests --- .../orders/getLiquidityProviderFee.test.ts | 45 +++++++++++++++++++ .../helpers/orders/makeOrderCalculations.ts | 13 ++---- 2 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts diff --git a/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts b/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts new file mode 100644 index 0000000000..63ccc03b78 --- /dev/null +++ b/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts @@ -0,0 +1,45 @@ +import {Quantities} from '../../utils/quantities' +import {getLiquidityProviderFee} from './getLiquidityProviderFee' +import {asQuantity} from '../../utils/asQuantity' + +describe('getLiquidityProviderFee', () => { + it('should return zero when sell quantity is zero', () => { + const result = getLiquidityProviderFee('0.03', { + tokenId: 'testToken', + quantity: Quantities.zero, + }) + + expect(result).toEqual({ + tokenId: 'testToken', + quantity: Quantities.zero, + }) + }) + + it('should calculate provider fee correctly based on sell side', () => { + const expectedFee = '300' + + const result = getLiquidityProviderFee('0.03', { + tokenId: 'testToken', + quantity: '1000000', + }) + + expect(result).toEqual({ + tokenId: 'testToken', + quantity: asQuantity(expectedFee), + }) + }) + + it('should calculate fee ceil up', () => { + const expectedFee = '66' + + const result = getLiquidityProviderFee('66.666666', { + tokenId: 'testToken', + quantity: '99', + }) + + expect(result).toEqual({ + tokenId: 'testToken', + quantity: asQuantity(expectedFee), + }) + }) +}) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 46fda6cbf5..a711db17e2 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -5,6 +5,7 @@ import { } from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' +import {getLiquidityProviderFee} from './getLiquidityProviderFee' export const makeOrderCalculations = ({ orderData, @@ -34,10 +35,8 @@ export const makeOrderCalculations = ({ orderCalculation = { cost: { - batcherFee: { - tokenId: primaryTokenId, - quantity: Quantities.zero, - }, + batcherFee: pool.batcherFee, + deposit: pool.deposit, frontendFeeInfo: { fee: { tokenId: primaryTokenId, @@ -45,11 +44,7 @@ export const makeOrderCalculations = ({ }, tier: undefined, }, - deposit: pool.deposit, - liquidityFee: { - tokenId: orderData.amounts.sell.tokenId, - quantity: Quantities.zero, - }, + liquidityFee: getLiquidityProviderFee(pool.fee, orderData.amounts.sell), }, buyAmountWithSlippage: { quantity: getQuantityWithSlippage( From d7ce781b9b1f5cecfc2aebcea47893db52fe502d Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 22:33:23 +0100 Subject: [PATCH 41/67] wip: frontend fee + lptoken --- .../helpers/orders/makeOrderCalculations.ts | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index a711db17e2..6cb307df57 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -6,17 +6,20 @@ import { import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' +import {getFrontendFee} from './getFrontendFee' export const makeOrderCalculations = ({ orderData, pools, primaryTokenId, action, + lpTokenHeld, }: Readonly<{ orderData: Swap.CreateOrderData pools: Array sellAmount: Balance.Amount buyAmount: Balance.Amount + lpTokenHeld: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] action: @@ -31,28 +34,37 @@ export const makeOrderCalculations = ({ const result: Array = [] pools.forEach((pool) => { - let orderCalculation: Writable + const buyAmountWithSlippage: Balance.Amount = { + quantity: getQuantityWithSlippage( + orderData.amounts.buy.quantity, + orderData.slippage, + ), + tokenId: orderData.amounts.buy.tokenId, + } + + const liquidityFee: Balance.Amount = getLiquidityProviderFee( + pool.fee, + orderData.amounts.sell, + ) - orderCalculation = { + const frontendFeeInfo = getFrontendFee({ + sell: orderData.amounts.sell, + buy: orderData.amounts.buy, + lpTokenHeld, + primaryTokenId: primaryTokenId, + // TODO: implement after adding the pair to ADA in the state + // sellInPrimaryTokenValue: orderData.sellInPrimaryTokenValue, + // buyInPrimaryTokenValue: orderData.buyInPrimaryTokenValue, + }) + + const orderCalculation: SwapOrderCalulation = { cost: { batcherFee: pool.batcherFee, deposit: pool.deposit, - frontendFeeInfo: { - fee: { - tokenId: primaryTokenId, - quantity: Quantities.zero, - }, - tier: undefined, - }, - liquidityFee: getLiquidityProviderFee(pool.fee, orderData.amounts.sell), - }, - buyAmountWithSlippage: { - quantity: getQuantityWithSlippage( - orderData.amounts.buy.quantity, - orderData.slippage, - ), - tokenId: orderData.amounts.buy.tokenId, + frontendFeeInfo, + liquidityFee, }, + buyAmountWithSlippage, sell: { price: '', priceDifference: '', From b7999a85f39c63b5fec499e7ceedbce739da472b Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:11:32 +0100 Subject: [PATCH 42/67] wip: price --- .../src/helpers/orders/makeOrderCalculations.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 6cb307df57..39458eb54b 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -7,14 +7,17 @@ import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' +import { getMarketPrice } from './getMarketPrice' export const makeOrderCalculations = ({ + orderType, orderData, pools, primaryTokenId, action, lpTokenHeld, }: Readonly<{ + orderType: Swap.OrderType orderData: Swap.CreateOrderData pools: Array sellAmount: Balance.Amount @@ -34,6 +37,15 @@ export const makeOrderCalculations = ({ const result: Array = [] pools.forEach((pool) => { + let price: string = '' + const marketPrice = getMarketPrice(pool, orderData.amounts.sell) + if (orderType === 'market') { + price = marketPrice + } else { + // NOTE: while editing should never receive undefined, otherwise it will replace with market price + price = orderData.limitPrice ?? marketPrice + } + const buyAmountWithSlippage: Balance.Amount = { quantity: getQuantityWithSlippage( orderData.amounts.buy.quantity, @@ -66,7 +78,7 @@ export const makeOrderCalculations = ({ }, buyAmountWithSlippage, sell: { - price: '', + price, priceDifference: '', priceWithFees: '', priceWithFeesAndSlippage: '', From 40a1d71cd2862b4e4b0d6074635d8c028263e2f1 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 2 Oct 2023 23:43:28 +0100 Subject: [PATCH 43/67] wip: sell/buy sides --- .../helpers/orders/makeOrderCalculations.ts | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 39458eb54b..095fa76c2d 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -7,7 +7,9 @@ import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' -import { getMarketPrice } from './getMarketPrice' +import {getMarketPrice} from './getMarketPrice' +import {getBuyAmount} from './getBuyAmount' +import { getSellAmount } from './getSellAmount' export const makeOrderCalculations = ({ orderType, @@ -25,6 +27,7 @@ export const makeOrderCalculations = ({ lpTokenHeld: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] + // TODO: guessing that later it will boils down to 2/3 scenarios action: | SwapCreateOrderActionType.SellQuantityChanged | SwapCreateOrderActionType.SellTokenIdChanged @@ -32,11 +35,38 @@ export const makeOrderCalculations = ({ | SwapCreateOrderActionType.BuyTokenIdChanged | SwapCreateOrderActionType.SlippageChanged | SwapCreateOrderActionType.PoolPairsChanged + | SwapCreateOrderActionType.OrderTypeChanged }>) => { - console.log(action) const result: Array = [] - pools.forEach((pool) => { + const isSellZero = Quantities.isZero(orderData.amounts.sell.quantity) + const isBuyZero = Quantities.isZero(orderData.amounts.buy.quantity) + const isLimit = orderType === 'limit' + + for (const pool of pools) { + let buy: Balance.Amount | undefined + if (action === SwapCreateOrderActionType.SellQuantityChanged) { + buy = getBuyAmount( + pool, + orderData.amounts.sell, + isLimit ? orderData.limitPrice : undefined, + ) + } + if (buy === undefined) buy = orderData.amounts.buy + + let sell: Balance.Amount | undefined + if (action === SwapCreateOrderActionType.BuyQuantityChanged) { + sell = getSellAmount( + pool, + orderData.amounts.buy, + isLimit ? orderData.limitPrice : undefined, + ) + } + if (sell === undefined) sell = orderData.amounts.sell + + console.log(buy, sell, isBuyZero, isSellZero) + + // TODO: if any side is zero set as 0 let price: string = '' const marketPrice = getMarketPrice(pool, orderData.amounts.sell) if (orderType === 'market') { @@ -90,7 +120,7 @@ export const makeOrderCalculations = ({ result.push(orderCalculation) // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? - }) + } return result } From 7f7cbf3e96be4c1a79caa6b72b41f2cbe7496939 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:32:36 +0100 Subject: [PATCH 44/67] wip: prices --- .../helpers/orders/makeOrderCalculations.ts | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 095fa76c2d..0edc78af1f 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -9,7 +9,7 @@ import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' -import { getSellAmount } from './getSellAmount' +import {getSellAmount} from './getSellAmount' export const makeOrderCalculations = ({ orderType, @@ -46,34 +46,48 @@ export const makeOrderCalculations = ({ for (const pool of pools) { let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { - buy = getBuyAmount( - pool, - orderData.amounts.sell, - isLimit ? orderData.limitPrice : undefined, - ) + if (isSellZero) { + buy = { + tokenId: orderData.amounts.buy.tokenId, + quantity: Quantities.zero, + } + } else { + buy = getBuyAmount( + pool, + orderData.amounts.sell, + isLimit ? orderData.limitPrice : undefined, + ) + } } if (buy === undefined) buy = orderData.amounts.buy let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - sell = getSellAmount( - pool, - orderData.amounts.buy, - isLimit ? orderData.limitPrice : undefined, - ) + if (isBuyZero) { + sell = { + tokenId: orderData.amounts.sell.tokenId, + quantity: Quantities.zero, + } + } else { + sell = getSellAmount( + pool, + orderData.amounts.buy, + isLimit ? orderData.limitPrice : undefined, + ) + } } if (sell === undefined) sell = orderData.amounts.sell console.log(buy, sell, isBuyZero, isSellZero) // TODO: if any side is zero set as 0 - let price: string = '' + let priceBase: string = '' const marketPrice = getMarketPrice(pool, orderData.amounts.sell) if (orderType === 'market') { - price = marketPrice + priceBase = marketPrice } else { // NOTE: while editing should never receive undefined, otherwise it will replace with market price - price = orderData.limitPrice ?? marketPrice + priceBase = orderData.limitPrice ?? marketPrice } const buyAmountWithSlippage: Balance.Amount = { @@ -107,12 +121,13 @@ export const makeOrderCalculations = ({ liquidityFee, }, buyAmountWithSlippage, - sell: { - price, - priceDifference: '', - priceWithFees: '', - priceWithFeesAndSlippage: '', - priceWithSlippage: '', + prices: { + base: priceBase, + market: marketPrice, + withFees: '', + difference: '', + withSlippage: '', + withFeesAndSlippage: '', }, pool, } From 2cc2ee69073ad0daee60ea18980017bac28e82cf Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:27:30 +0100 Subject: [PATCH 45/67] wip: prices --- .../helpers/orders/makeOrderCalculations.ts | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 0edc78af1f..f61a883f73 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -14,6 +14,7 @@ import {getSellAmount} from './getSellAmount' export const makeOrderCalculations = ({ orderType, orderData, + ptPrices, pools, primaryTokenId, action, @@ -21,6 +22,10 @@ export const makeOrderCalculations = ({ }: Readonly<{ orderType: Swap.OrderType orderData: Swap.CreateOrderData + ptPrices: { + buy: string + sell: string + } pools: Array sellAmount: Balance.Amount buyAmount: Balance.Amount @@ -44,6 +49,7 @@ export const makeOrderCalculations = ({ const isLimit = orderType === 'limit' for (const pool of pools) { + // when changing sell quantity, calculate buy quantity let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { if (isSellZero) { @@ -61,6 +67,7 @@ export const makeOrderCalculations = ({ } if (buy === undefined) buy = orderData.amounts.buy + // when changing buy quantity, calculate sell quantity let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { if (isBuyZero) { @@ -78,18 +85,22 @@ export const makeOrderCalculations = ({ } if (sell === undefined) sell = orderData.amounts.sell - console.log(buy, sell, isBuyZero, isSellZero) + // when changing sell token ? + // when changing buy token ? + // when changing pool - limit order ? + // when changing price - limit order ? - // TODO: if any side is zero set as 0 - let priceBase: string = '' + // recalculate price base, limit is user's input, market from pool + let priceBase: string const marketPrice = getMarketPrice(pool, orderData.amounts.sell) if (orderType === 'market') { priceBase = marketPrice } else { - // NOTE: while editing should never receive undefined, otherwise it will replace with market price + // NOTE: while editing should never receive undefined or '', undefined = market price, '' = NaN priceBase = orderData.limitPrice ?? marketPrice } + // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { quantity: getQuantityWithSlippage( orderData.amounts.buy.quantity, @@ -98,11 +109,13 @@ export const makeOrderCalculations = ({ tokenId: orderData.amounts.buy.tokenId, } + // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee( pool.fee, orderData.amounts.sell, ) + // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ sell: orderData.amounts.sell, buy: orderData.amounts.buy, @@ -124,10 +137,10 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: '', - difference: '', - withSlippage: '', - withFeesAndSlippage: '', + withFees: '0', + difference: '0', + withSlippage: '0', + withFeesAndSlippage: '0', }, pool, } From 70d284dbd3f348ed8ed57af0140051dc2d308926 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:32:48 +0100 Subject: [PATCH 46/67] wip: helpers dealt with 0 --- .../helpers/orders/makeOrderCalculations.ts | 40 ++++++------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index f61a883f73..49922f6f61 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -44,44 +44,28 @@ export const makeOrderCalculations = ({ }>) => { const result: Array = [] - const isSellZero = Quantities.isZero(orderData.amounts.sell.quantity) - const isBuyZero = Quantities.isZero(orderData.amounts.buy.quantity) const isLimit = orderType === 'limit' for (const pool of pools) { - // when changing sell quantity, calculate buy quantity + // when changing sell quantity, calculate buy quantity based on order type let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { - if (isSellZero) { - buy = { - tokenId: orderData.amounts.buy.tokenId, - quantity: Quantities.zero, - } - } else { - buy = getBuyAmount( - pool, - orderData.amounts.sell, - isLimit ? orderData.limitPrice : undefined, - ) - } + buy = getBuyAmount( + pool, + orderData.amounts.sell, + isLimit ? orderData.limitPrice : undefined, + ) } if (buy === undefined) buy = orderData.amounts.buy - // when changing buy quantity, calculate sell quantity + // when changing buy quantity, calculate sell quantity based on order type let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - if (isBuyZero) { - sell = { - tokenId: orderData.amounts.sell.tokenId, - quantity: Quantities.zero, - } - } else { - sell = getSellAmount( - pool, - orderData.amounts.buy, - isLimit ? orderData.limitPrice : undefined, - ) - } + sell = getSellAmount( + pool, + orderData.amounts.buy, + isLimit ? orderData.limitPrice : undefined, + ) } if (sell === undefined) sell = orderData.amounts.sell From 875b08816cbd9787b10ac700c95793ecbdcad815 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:40:13 +0100 Subject: [PATCH 47/67] wip: price with fees --- .../helpers/orders/makeOrderCalculations.ts | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 49922f6f61..cc4d96f330 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,4 +1,5 @@ import {Balance, Swap, Writable} from '@yoroi/types' +import {BigNumber} from 'bignumber.js' import { SwapCreateOrderActionType, SwapOrderCalulation, @@ -10,6 +11,7 @@ import {getFrontendFee} from './getFrontendFee' import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' import {getSellAmount} from './getSellAmount' +import {asQuantity} from '../../utils/asQuantity' export const makeOrderCalculations = ({ orderType, @@ -105,11 +107,41 @@ export const makeOrderCalculations = ({ buy: orderData.amounts.buy, lpTokenHeld, primaryTokenId: primaryTokenId, - // TODO: implement after adding the pair to ADA in the state - // sellInPrimaryTokenValue: orderData.sellInPrimaryTokenValue, - // buyInPrimaryTokenValue: orderData.buyInPrimaryTokenValue, + sellInPrimaryTokenValue: { + tokenId: primaryTokenId, + quantity: asQuantity( + new BigNumber(orderData.amounts.sell.quantity) + .times(ptPrices.sell) + .integerValue(BigNumber.ROUND_CEIL), + ), + }, + buyInPrimaryTokenValue: { + tokenId: primaryTokenId, + quantity: asQuantity( + new BigNumber(orderData.amounts.buy.quantity) + .times(ptPrices.buy) + .integerValue(BigNumber.ROUND_CEIL), + ), + }, }) + // transform fees in terms of sell side quantity * pt price (unit of fees) + const feeInSellSideQuantities = { + batcherFee: new BigNumber(pool.batcherFee.quantity) + .times(ptPrices.sell) + .integerValue(BigNumber.ROUND_CEIL), + frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) + .times(ptPrices.sell) + .integerValue(BigNumber.ROUND_CEIL), + } + + // add up all that's being sold in sell terms + const priceWithFees = new BigNumber(sell.quantity) + .plus(feeInSellSideQuantities.batcherFee) + .plus(feeInSellSideQuantities.frontendFee) + .dividedBy(new BigNumber(buy.quantity)) + .toString() + const orderCalculation: SwapOrderCalulation = { cost: { batcherFee: pool.batcherFee, @@ -121,7 +153,8 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: '0', + withFees: priceWithFees, + // TODO: add later difference: '0', withSlippage: '0', withFeesAndSlippage: '0', From a8162037bf70c1b928b5959db1a9e1fe72c9a122 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:29:03 +0100 Subject: [PATCH 48/67] wip: price difference --- .../helpers/orders/makeOrderCalculations.ts | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index cc4d96f330..6b5a9da46b 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -43,6 +43,8 @@ export const makeOrderCalculations = ({ | SwapCreateOrderActionType.SlippageChanged | SwapCreateOrderActionType.PoolPairsChanged | SwapCreateOrderActionType.OrderTypeChanged + | SwapCreateOrderActionType.SwitchTokens + | SwapCreateOrderActionType.LimitPriceChanged }>) => { const result: Array = [] @@ -126,6 +128,7 @@ export const makeOrderCalculations = ({ }) // transform fees in terms of sell side quantity * pt price (unit of fees) + // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) .times(ptPrices.sell) @@ -136,10 +139,25 @@ export const makeOrderCalculations = ({ } // add up all that's being sold in sell terms - const priceWithFees = new BigNumber(sell.quantity) + const sellWithFees = new BigNumber(sell.quantity) .plus(feeInSellSideQuantities.batcherFee) .plus(feeInSellSideQuantities.frontendFee) - .dividedBy(new BigNumber(buy.quantity)) + + const priceWithFees = sellWithFees.dividedBy(buy.quantity) + + const priceWithSlippage = new BigNumber(sell.quantity) + .dividedBy(buyAmountWithSlippage.quantity) + .toString() + + const priceWithFeesAndSlippage = sellWithFees + .dividedBy(buyAmountWithSlippage.quantity) + .toString() + + // always based, if is limit it can lead to a weird percentage + const priceDifference = priceWithFees + .minus(priceBase) + .dividedBy(priceBase) + .times(100) .toString() const orderCalculation: SwapOrderCalulation = { @@ -153,11 +171,10 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: priceWithFees, - // TODO: add later - difference: '0', - withSlippage: '0', - withFeesAndSlippage: '0', + withFees: priceWithFees.toString(), + withSlippage: priceWithSlippage, + withFeesAndSlippage: priceWithFeesAndSlippage, + difference: priceDifference, }, pool, } From 41e0e30f2559138b0ca75b3a904cf1a83e4bbc0b Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 16:37:07 +0100 Subject: [PATCH 49/67] wip: state --- .../helpers/orders/makeOrderCalculations.ts | 89 +++++++++---------- 1 file changed, 43 insertions(+), 46 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 6b5a9da46b..d2a2eed026 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,11 +1,10 @@ -import {Balance, Swap, Writable} from '@yoroi/types' +import {Balance, Swap} from '@yoroi/types' import {BigNumber} from 'bignumber.js' import { SwapCreateOrderActionType, SwapOrderCalulation, } from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' -import {Quantities} from '../../utils/quantities' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' import {getMarketPrice} from './getMarketPrice' @@ -15,113 +14,111 @@ import {asQuantity} from '../../utils/asQuantity' export const makeOrderCalculations = ({ orderType, - orderData, + amounts, + limitPrice, + slippage, ptPrices, pools, primaryTokenId, - action, lpTokenHeld, + action, }: Readonly<{ orderType: Swap.OrderType - orderData: Swap.CreateOrderData + amounts: { + sell: Balance.Amount + buy: Balance.Amount + } + limitPrice: `${number}` | undefined ptPrices: { - buy: string - sell: string + buy: `${number}` | undefined + sell: `${number}` | undefined } - pools: Array - sellAmount: Balance.Amount - buyAmount: Balance.Amount - lpTokenHeld: Balance.Amount + pools: ReadonlyArray + lpTokenHeld: Balance.Amount | undefined slippage: number primaryTokenId: Balance.TokenInfo['id'] // TODO: guessing that later it will boils down to 2/3 scenarios action: | SwapCreateOrderActionType.SellQuantityChanged - | SwapCreateOrderActionType.SellTokenIdChanged | SwapCreateOrderActionType.BuyQuantityChanged + // same bag for now + | SwapCreateOrderActionType.SellTokenIdChanged | SwapCreateOrderActionType.BuyTokenIdChanged | SwapCreateOrderActionType.SlippageChanged | SwapCreateOrderActionType.PoolPairsChanged | SwapCreateOrderActionType.OrderTypeChanged | SwapCreateOrderActionType.SwitchTokens | SwapCreateOrderActionType.LimitPriceChanged + | SwapCreateOrderActionType.ResetQuantities + | SwapCreateOrderActionType.LpTokenHeldChanged }>) => { const result: Array = [] - const isLimit = orderType === 'limit' + // when changing sell token ? + // when changing buy token ? + // when changing pool - limit order ? + // when changing price - limit order ? + // when switching sell/buy + // when changing slippage + for (const pool of pools) { // when changing sell quantity, calculate buy quantity based on order type let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { - buy = getBuyAmount( - pool, - orderData.amounts.sell, - isLimit ? orderData.limitPrice : undefined, - ) + buy = getBuyAmount(pool, amounts.sell, isLimit ? limitPrice : undefined) } - if (buy === undefined) buy = orderData.amounts.buy + if (buy === undefined) buy = amounts.buy // when changing buy quantity, calculate sell quantity based on order type let sell: Balance.Amount | undefined if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - sell = getSellAmount( - pool, - orderData.amounts.buy, - isLimit ? orderData.limitPrice : undefined, - ) + sell = getSellAmount(pool, amounts.buy, isLimit ? limitPrice : undefined) } - if (sell === undefined) sell = orderData.amounts.sell - - // when changing sell token ? - // when changing buy token ? - // when changing pool - limit order ? - // when changing price - limit order ? + if (sell === undefined) sell = amounts.sell // recalculate price base, limit is user's input, market from pool let priceBase: string - const marketPrice = getMarketPrice(pool, orderData.amounts.sell) + const marketPrice = getMarketPrice(pool, amounts.sell) if (orderType === 'market') { priceBase = marketPrice } else { // NOTE: while editing should never receive undefined or '', undefined = market price, '' = NaN - priceBase = orderData.limitPrice ?? marketPrice + // when switching sell/buy limit is kept + priceBase = limitPrice ?? marketPrice } // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { - quantity: getQuantityWithSlippage( - orderData.amounts.buy.quantity, - orderData.slippage, - ), - tokenId: orderData.amounts.buy.tokenId, + quantity: getQuantityWithSlippage(amounts.buy.quantity, slippage), + tokenId: amounts.buy.tokenId, } // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee( pool.fee, - orderData.amounts.sell, + amounts.sell, ) // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ - sell: orderData.amounts.sell, - buy: orderData.amounts.buy, + sell: amounts.sell, + buy: amounts.buy, lpTokenHeld, primaryTokenId: primaryTokenId, sellInPrimaryTokenValue: { tokenId: primaryTokenId, quantity: asQuantity( - new BigNumber(orderData.amounts.sell.quantity) - .times(ptPrices.sell) + new BigNumber(amounts.sell.quantity) + .times(ptPrices.sell ?? 0) .integerValue(BigNumber.ROUND_CEIL), ), }, buyInPrimaryTokenValue: { tokenId: primaryTokenId, quantity: asQuantity( - new BigNumber(orderData.amounts.buy.quantity) - .times(ptPrices.buy) + new BigNumber(amounts.buy.quantity) + .times(ptPrices.buy ?? 0) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -131,10 +128,10 @@ export const makeOrderCalculations = ({ // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) - .times(ptPrices.sell) + .times(ptPrices.sell ?? 0) .integerValue(BigNumber.ROUND_CEIL), frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .times(ptPrices.sell) + .times(ptPrices.sell ?? 0) .integerValue(BigNumber.ROUND_CEIL), } From ccc6e2529aa53e31c418fb331f15bc0c4f3c0744 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 17:58:10 +0100 Subject: [PATCH 50/67] wip: state --- packages/swap/src/helpers/orders/makeOrderCalculations.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index d2a2eed026..6936186627 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -62,7 +62,7 @@ export const makeOrderCalculations = ({ // when switching sell/buy // when changing slippage - for (const pool of pools) { + pools.forEach((pool) => { // when changing sell quantity, calculate buy quantity based on order type let buy: Balance.Amount | undefined if (action === SwapCreateOrderActionType.SellQuantityChanged) { @@ -179,7 +179,7 @@ export const makeOrderCalculations = ({ result.push(orderCalculation) // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? - } + }) return result } From dffa342508e363baf744b0b8f9349774083ad785 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 21:55:27 +0100 Subject: [PATCH 51/67] wip: state --- packages/swap/src/helpers/orders/makeOrderCalculations.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 6936186627..f4aacbb670 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -61,6 +61,8 @@ export const makeOrderCalculations = ({ // when changing price - limit order ? // when switching sell/buy // when changing slippage + // when changing the lp token held + // when reseting quantities pools.forEach((pool) => { // when changing sell quantity, calculate buy quantity based on order type From b66465fac1cbbb1ae41845efdc5824d4406ef21f Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Tue, 3 Oct 2023 22:59:06 +0100 Subject: [PATCH 52/67] wip: added getPrice --- .../src/adapters/openswap-api/api.test.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/swap/src/adapters/openswap-api/api.test.ts b/packages/swap/src/adapters/openswap-api/api.test.ts index 4c85ad8fb7..90af260936 100644 --- a/packages/swap/src/adapters/openswap-api/api.test.ts +++ b/packages/swap/src/adapters/openswap-api/api.test.ts @@ -345,4 +345,32 @@ describe('swapApiMaker', () => { expect(mockOpenSwapApi.getPrice).toHaveBeenCalledTimes(1) }) }) + + describe('getPrice', () => { + it('mainnet', async () => { + mockOpenSwapApi.getPrice = jest + .fn() + .mockResolvedValue(openswapMocks.getPrice) + + const api = swapApiMaker( + { + isMainnet: true, + stakingKey, + primaryTokenId, + }, + { + openswap: mockOpenSwapApi, + }, + ) + + const result = await api.getPrice({ + baseToken: '', + quoteToken: + '29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c6.4d494e', + }) + + expect(result).toBe(0.07080044463) + expect(mockOpenSwapApi.getPrice).toHaveBeenCalledTimes(1) + }) + }) }) From 7efa5eec68fc83b605e80fd42710616301e666b7 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Wed, 4 Oct 2023 08:49:25 +0100 Subject: [PATCH 53/67] wip: state --- .../reactjs/provider/SwapProvider.tsx | 14 +++++++++---- .../translators/reactjs/state/state.test.ts | 21 +++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx index 194d232c82..762dc31f25 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx @@ -79,11 +79,17 @@ export const SwapProvider = ({ lpTokenHeldChanged: (amount: Balance.Amount | undefined) => { dispatch({type: SwapCreateOrderActionType.LpTokenHeldChanged, amount}) }, - buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { - dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, tokenId}) + buyTokenIdChanged: (payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + }) => { + dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, payload}) }, - sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { - dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, tokenId}) + sellTokenIdChanged: (payload: { + tokenId: Balance.TokenInfo['id'] + pools: ReadonlyArray + }) => { + dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, payload}) }, poolPairsChanged: (pools: ReadonlyArray) => { dispatch({type: SwapCreateOrderActionType.PoolPairsChanged, pools}) diff --git a/packages/swap/src/translators/reactjs/state/state.test.ts b/packages/swap/src/translators/reactjs/state/state.test.ts index 9f1e2f3a3c..2ea182fe02 100644 --- a/packages/swap/src/translators/reactjs/state/state.test.ts +++ b/packages/swap/src/translators/reactjs/state/state.test.ts @@ -196,4 +196,25 @@ describe('State Actions', () => { it('LpTokenHeldChanged', () => { expect('todo').toBeDefined() }) + + // + // TODO: implement + it('SellTokenIdChanged', () => { + expect('todo').toBeDefined() + }) + it('BuyTokenIdChanged', () => { + expect('todo').toBeDefined() + }) + it('SellQuantityChanged', () => { + expect('todo').toBeDefined() + }) + it('BuyQuantityChanged', () => { + expect('todo').toBeDefined() + }) + it('PoolPairsChanged', () => { + expect('todo').toBeDefined() + }) + it('LpTokenHeldChanged', () => { + expect('todo').toBeDefined() + }) }) From 0240a8d6364e018ce57e74ac6dc77f7819618ace Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Wed, 4 Oct 2023 08:59:10 +0100 Subject: [PATCH 54/67] wip: calcs --- .../swap/src/helpers/orders/makeOrderCalculations.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index f4aacbb670..5bf2a55a38 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -11,6 +11,7 @@ import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' import {getSellAmount} from './getSellAmount' import {asQuantity} from '../../utils/asQuantity' +import {Quantities} from 'utils/quantities' export const makeOrderCalculations = ({ orderType, @@ -33,6 +34,7 @@ export const makeOrderCalculations = ({ buy: `${number}` | undefined sell: `${number}` | undefined } + hasSupply: boolean, pools: ReadonlyArray lpTokenHeld: Balance.Amount | undefined slippage: number @@ -159,6 +161,15 @@ export const makeOrderCalculations = ({ .times(100) .toString() + const poolSupply = + buy.tokenId === pool.tokenA.tokenId + ? pool.tokenA.quantity + : pool.tokenB.quantity + const hasSupply = !Quantities.isGreaterThan( + buy.quantity, + poolSupply ?? Quantities.zero, + ) + const orderCalculation: SwapOrderCalulation = { cost: { batcherFee: pool.batcherFee, @@ -167,6 +178,7 @@ export const makeOrderCalculations = ({ liquidityFee, }, buyAmountWithSlippage, + hasSupply, prices: { base: priceBase, market: marketPrice, From 7b546d34a161de195f949e0f046e5c1d38550905 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Thu, 5 Oct 2023 18:42:08 +0200 Subject: [PATCH 55/67] Refactor calculaed state --- .../helpers/orders/makeOrderCalculations.ts | 113 +++++------------- .../translators/reactjs/state/state.test.ts | 21 ---- 2 files changed, 33 insertions(+), 101 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 5bf2a55a38..254ca052b3 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,9 +1,6 @@ import {Balance, Swap} from '@yoroi/types' import {BigNumber} from 'bignumber.js' -import { - SwapCreateOrderActionType, - SwapOrderCalulation, -} from '../../translators/reactjs/state/state' +import {SwapOrderCalulation} from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' @@ -11,7 +8,7 @@ import {getMarketPrice} from './getMarketPrice' import {getBuyAmount} from './getBuyAmount' import {getSellAmount} from './getSellAmount' import {asQuantity} from '../../utils/asQuantity' -import {Quantities} from 'utils/quantities' +import {Quantities} from '../../utils/quantities' export const makeOrderCalculations = ({ orderType, @@ -29,87 +26,49 @@ export const makeOrderCalculations = ({ sell: Balance.Amount buy: Balance.Amount } - limitPrice: `${number}` | undefined + limitPrice?: Balance.Quantity ptPrices: { - buy: `${number}` | undefined - sell: `${number}` | undefined + buy?: Balance.Quantity + sell?: Balance.Quantity } - hasSupply: boolean, pools: ReadonlyArray - lpTokenHeld: Balance.Amount | undefined + lpTokenHeld?: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] - // TODO: guessing that later it will boils down to 2/3 scenarios - action: - | SwapCreateOrderActionType.SellQuantityChanged - | SwapCreateOrderActionType.BuyQuantityChanged - // same bag for now - | SwapCreateOrderActionType.SellTokenIdChanged - | SwapCreateOrderActionType.BuyTokenIdChanged - | SwapCreateOrderActionType.SlippageChanged - | SwapCreateOrderActionType.PoolPairsChanged - | SwapCreateOrderActionType.OrderTypeChanged - | SwapCreateOrderActionType.SwitchTokens - | SwapCreateOrderActionType.LimitPriceChanged - | SwapCreateOrderActionType.ResetQuantities - | SwapCreateOrderActionType.LpTokenHeldChanged -}>) => { - const result: Array = [] + action?: 'buy' | 'sell' +}>): Array => { const isLimit = orderType === 'limit' - - // when changing sell token ? - // when changing buy token ? - // when changing pool - limit order ? - // when changing price - limit order ? - // when switching sell/buy - // when changing slippage - // when changing the lp token held - // when reseting quantities - - pools.forEach((pool) => { - // when changing sell quantity, calculate buy quantity based on order type - let buy: Balance.Amount | undefined - if (action === SwapCreateOrderActionType.SellQuantityChanged) { - buy = getBuyAmount(pool, amounts.sell, isLimit ? limitPrice : undefined) - } - if (buy === undefined) buy = amounts.buy - - // when changing buy quantity, calculate sell quantity based on order type - let sell: Balance.Amount | undefined - if (action === SwapCreateOrderActionType.BuyQuantityChanged) { - sell = getSellAmount(pool, amounts.buy, isLimit ? limitPrice : undefined) - } - if (sell === undefined) sell = amounts.sell - + const maybeLimitPrice = isLimit ? limitPrice : undefined + + return pools.map((pool) => { + const buy = + action === 'sell' + ? getBuyAmount(pool, amounts.sell, maybeLimitPrice) + : amounts.buy + const sell = + action === 'buy' + ? getSellAmount(pool, amounts.buy, maybeLimitPrice) + : amounts.sell + + const marketPrice = getMarketPrice(pool, sell) // recalculate price base, limit is user's input, market from pool - let priceBase: string - const marketPrice = getMarketPrice(pool, amounts.sell) - if (orderType === 'market') { - priceBase = marketPrice - } else { - // NOTE: while editing should never receive undefined or '', undefined = market price, '' = NaN - // when switching sell/buy limit is kept - priceBase = limitPrice ?? marketPrice - } + const priceBase = isLimit ? limitPrice ?? marketPrice : marketPrice // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { - quantity: getQuantityWithSlippage(amounts.buy.quantity, slippage), - tokenId: amounts.buy.tokenId, + quantity: getQuantityWithSlippage(buy.quantity, slippage), + tokenId: buy.tokenId, } // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken - const liquidityFee: Balance.Amount = getLiquidityProviderFee( - pool.fee, - amounts.sell, - ) + const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ - sell: amounts.sell, - buy: amounts.buy, + sell, + buy, lpTokenHeld, - primaryTokenId: primaryTokenId, + primaryTokenId, sellInPrimaryTokenValue: { tokenId: primaryTokenId, quantity: asQuantity( @@ -170,7 +129,7 @@ export const makeOrderCalculations = ({ poolSupply ?? Quantities.zero, ) - const orderCalculation: SwapOrderCalulation = { + return { cost: { batcherFee: pool.batcherFee, deposit: pool.deposit, @@ -182,18 +141,12 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: priceWithFees.toString(), - withSlippage: priceWithSlippage, - withFeesAndSlippage: priceWithFeesAndSlippage, - difference: priceDifference, + withFees: asQuantity(priceWithFees), + withSlippage: asQuantity(priceWithSlippage), + withFeesAndSlippage: asQuantity(priceWithFeesAndSlippage), + difference: asQuantity(priceDifference), }, pool, } - - result.push(orderCalculation) - - // TODO: decide the "best" pool later, we need to define "best", maybe lowest price after fees? }) - - return result } diff --git a/packages/swap/src/translators/reactjs/state/state.test.ts b/packages/swap/src/translators/reactjs/state/state.test.ts index 2ea182fe02..9f1e2f3a3c 100644 --- a/packages/swap/src/translators/reactjs/state/state.test.ts +++ b/packages/swap/src/translators/reactjs/state/state.test.ts @@ -196,25 +196,4 @@ describe('State Actions', () => { it('LpTokenHeldChanged', () => { expect('todo').toBeDefined() }) - - // - // TODO: implement - it('SellTokenIdChanged', () => { - expect('todo').toBeDefined() - }) - it('BuyTokenIdChanged', () => { - expect('todo').toBeDefined() - }) - it('SellQuantityChanged', () => { - expect('todo').toBeDefined() - }) - it('BuyQuantityChanged', () => { - expect('todo').toBeDefined() - }) - it('PoolPairsChanged', () => { - expect('todo').toBeDefined() - }) - it('LpTokenHeldChanged', () => { - expect('todo').toBeDefined() - }) }) From 0d7b766965be3527b06a7a1d4bc2f84cb118d540 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Thu, 5 Oct 2023 21:28:39 +0200 Subject: [PATCH 56/67] Fix calculatedPool --- .../helpers/orders/makeOrderCalculations.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 254ca052b3..cb7e3cbca6 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -1,6 +1,6 @@ import {Balance, Swap} from '@yoroi/types' import {BigNumber} from 'bignumber.js' -import {SwapOrderCalulation} from '../../translators/reactjs/state/state' +import {SwapOrderCalculation} from '../../translators/reactjs/state/state' import {getQuantityWithSlippage} from './getQuantityWithSlippage' import {getLiquidityProviderFee} from './getLiquidityProviderFee' import {getFrontendFee} from './getFrontendFee' @@ -36,11 +36,11 @@ export const makeOrderCalculations = ({ slippage: number primaryTokenId: Balance.TokenInfo['id'] action?: 'buy' | 'sell' -}>): Array => { +}>): Array => { const isLimit = orderType === 'limit' const maybeLimitPrice = isLimit ? limitPrice : undefined - return pools.map((pool) => { + return pools.map((pool) => { const buy = action === 'sell' ? getBuyAmount(pool, amounts.sell, maybeLimitPrice) @@ -103,15 +103,19 @@ export const makeOrderCalculations = ({ .plus(feeInSellSideQuantities.batcherFee) .plus(feeInSellSideQuantities.frontendFee) - const priceWithFees = sellWithFees.dividedBy(buy.quantity) + const priceWithFees = Quantities.isZero(buy.quantity) + ? new BigNumber(0) + : sellWithFees.dividedBy(buy.quantity) - const priceWithSlippage = new BigNumber(sell.quantity) - .dividedBy(buyAmountWithSlippage.quantity) - .toString() + const priceWithSlippage = Quantities.isZero(buy.quantity) + ? Quantities.zero + : new BigNumber(sell.quantity) + .dividedBy(buyAmountWithSlippage.quantity) + .toString() - const priceWithFeesAndSlippage = sellWithFees - .dividedBy(buyAmountWithSlippage.quantity) - .toString() + const priceWithFeesAndSlippage = Quantities.isZero(buy.quantity) + ? Quantities.zero + : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() // always based, if is limit it can lead to a weird percentage const priceDifference = priceWithFees From d49eb0fa9e64a2c846e98d7a401052c3ee830325 Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Fri, 6 Oct 2023 12:04:19 +0200 Subject: [PATCH 57/67] Add calc for fees without frontend fee --- .../helpers/orders/makeOrderCalculations.ts | 94 ++++++++++++------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index cb7e3cbca6..417fc5022e 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -60,6 +60,15 @@ export const makeOrderCalculations = ({ tokenId: buy.tokenId, } + const poolSupply = + buy.tokenId === pool.tokenA.tokenId + ? pool.tokenA.quantity + : pool.tokenB.quantity + const hasSupply = !Quantities.isGreaterThan( + buy.quantity, + poolSupply ?? Quantities.zero, + ) + // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) @@ -98,41 +107,57 @@ export const makeOrderCalculations = ({ .integerValue(BigNumber.ROUND_CEIL), } - // add up all that's being sold in sell terms - const sellWithFees = new BigNumber(sell.quantity) - .plus(feeInSellSideQuantities.batcherFee) - .plus(feeInSellSideQuantities.frontendFee) + const priceWithSlippage = Quantities.isZero(buyAmountWithSlippage.quantity) + ? Quantities.zero + : asQuantity( + new BigNumber(sell.quantity) + .dividedBy(buyAmountWithSlippage.quantity) + .toString(), + ) - const priceWithFees = Quantities.isZero(buy.quantity) - ? new BigNumber(0) - : sellWithFees.dividedBy(buy.quantity) + const calculatePricesWithFees = (withFrontendFee?: boolean) => { + // add up all that's being sold in sell terms + const sellWithBatcher = new BigNumber(sell.quantity).plus( + feeInSellSideQuantities.batcherFee, + ) + const sellWithFees = withFrontendFee + ? sellWithBatcher.plus(feeInSellSideQuantities.frontendFee) + : sellWithBatcher - const priceWithSlippage = Quantities.isZero(buy.quantity) - ? Quantities.zero - : new BigNumber(sell.quantity) - .dividedBy(buyAmountWithSlippage.quantity) - .toString() + const priceWithFees = Quantities.isZero(buy.quantity) + ? new BigNumber(0) + : sellWithFees.dividedBy(buy.quantity) - const priceWithFeesAndSlippage = Quantities.isZero(buy.quantity) - ? Quantities.zero - : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() + const priceWithFeesAndSlippage = Quantities.isZero( + buyAmountWithSlippage.quantity, + ) + ? Quantities.zero + : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() - // always based, if is limit it can lead to a weird percentage - const priceDifference = priceWithFees - .minus(priceBase) - .dividedBy(priceBase) - .times(100) - .toString() + // always based, if is limit it can lead to a weird percentage + const priceDifference = priceWithFees + .minus(priceBase) + .dividedBy(priceBase) + .times(100) + .toString() - const poolSupply = - buy.tokenId === pool.tokenA.tokenId - ? pool.tokenA.quantity - : pool.tokenB.quantity - const hasSupply = !Quantities.isGreaterThan( - buy.quantity, - poolSupply ?? Quantities.zero, - ) + return { + priceWithFees: asQuantity(priceWithFees), + priceWithFeesAndSlippage: asQuantity(priceWithFeesAndSlippage), + priceDifference: asQuantity(priceDifference), + } + } + const { + priceWithFees: withFees, + priceWithFeesAndSlippage: withFeesAndSlippage, + priceDifference: difference, + } = calculatePricesWithFees(true) + const { + priceWithFees: withFeesNoFEF, + priceWithFeesAndSlippage: withFeesAndSlippageNoFEF, + priceDifference: differenceNoFEF, + } = calculatePricesWithFees(false) return { cost: { batcherFee: pool.batcherFee, @@ -145,10 +170,13 @@ export const makeOrderCalculations = ({ prices: { base: priceBase, market: marketPrice, - withFees: asQuantity(priceWithFees), - withSlippage: asQuantity(priceWithSlippage), - withFeesAndSlippage: asQuantity(priceWithFeesAndSlippage), - difference: asQuantity(priceDifference), + withSlippage: priceWithSlippage, + withFees, + withFeesAndSlippage, + difference, + withFeesNoFEF, + withFeesAndSlippageNoFEF, + differenceNoFEF, }, pool, } From a25585e58cf19173c6c88d4e8abba1fc9a5235ca Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Sat, 7 Oct 2023 11:46:58 +0100 Subject: [PATCH 58/67] chore: dropped state pt prices in favor of pool pt price --- .../helpers/orders/makeOrderCalculations.ts | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 417fc5022e..4a92014d28 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -15,7 +15,6 @@ export const makeOrderCalculations = ({ amounts, limitPrice, slippage, - ptPrices, pools, primaryTokenId, lpTokenHeld, @@ -27,10 +26,6 @@ export const makeOrderCalculations = ({ buy: Balance.Amount } limitPrice?: Balance.Quantity - ptPrices: { - buy?: Balance.Quantity - sell?: Balance.Quantity - } pools: ReadonlyArray lpTokenHeld?: Balance.Amount slippage: number @@ -60,10 +55,9 @@ export const makeOrderCalculations = ({ tokenId: buy.tokenId, } - const poolSupply = - buy.tokenId === pool.tokenA.tokenId - ? pool.tokenA.quantity - : pool.tokenB.quantity + // pools that with not enough supply will be filtered out + const isBuyTokenA = buy.tokenId === pool.tokenA.tokenId + const poolSupply = isBuyTokenA ? pool.tokenA.quantity : pool.tokenB.quantity const hasSupply = !Quantities.isGreaterThan( buy.quantity, poolSupply ?? Quantities.zero, @@ -72,6 +66,10 @@ export const makeOrderCalculations = ({ // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) + const [ptPriceBuy, ptPriceSell] = isBuyTokenA + ? [pool.ptPriceTokenA, pool.ptPriceTokenB] + : [pool.ptPriceTokenB, pool.ptPriceTokenA] + // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) const frontendFeeInfo = getFrontendFee({ sell, @@ -82,7 +80,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.sell.quantity) - .times(ptPrices.sell ?? 0) + .times(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -90,7 +88,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.buy.quantity) - .times(ptPrices.buy ?? 0) + .times(ptPriceBuy) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -100,10 +98,10 @@ export const makeOrderCalculations = ({ // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) - .times(ptPrices.sell ?? 0) + .times(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .times(ptPrices.sell ?? 0) + .times(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), } From 0e5d7fb36ffb20412578364473e80deb02b96055 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Sun, 8 Oct 2023 23:38:40 +0100 Subject: [PATCH 59/67] chore: clean state --- .../helpers/orders/makeOrderCalculations.ts | 56 +++++++++++++------ .../reactjs/provider/SwapProvider.tsx | 14 ++--- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 4a92014d28..648eb4fafc 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -18,7 +18,7 @@ export const makeOrderCalculations = ({ pools, primaryTokenId, lpTokenHeld, - action, + side, }: Readonly<{ orderType: Swap.OrderType amounts: { @@ -30,24 +30,24 @@ export const makeOrderCalculations = ({ lpTokenHeld?: Balance.Amount slippage: number primaryTokenId: Balance.TokenInfo['id'] - action?: 'buy' | 'sell' + side?: 'buy' | 'sell' }>): Array => { const isLimit = orderType === 'limit' const maybeLimitPrice = isLimit ? limitPrice : undefined - return pools.map((pool) => { + const calculations = pools.map((pool) => { const buy = - action === 'sell' + side === 'sell' ? getBuyAmount(pool, amounts.sell, maybeLimitPrice) : amounts.buy const sell = - action === 'buy' + side === 'buy' ? getSellAmount(pool, amounts.buy, maybeLimitPrice) : amounts.sell const marketPrice = getMarketPrice(pool, sell) // recalculate price base, limit is user's input, market from pool - const priceBase = isLimit ? limitPrice ?? marketPrice : marketPrice + const priceBase = maybeLimitPrice ?? marketPrice // calculate buy quantity with slippage const buyAmountWithSlippage: Balance.Amount = { @@ -113,7 +113,11 @@ export const makeOrderCalculations = ({ .toString(), ) - const calculatePricesWithFees = (withFrontendFee?: boolean) => { + const calculatePricesWithFees = ({ + withFrontendFee, + }: { + withFrontendFee?: boolean + }) => { // add up all that's being sold in sell terms const sellWithBatcher = new BigNumber(sell.quantity).plus( feeInSellSideQuantities.batcherFee, @@ -133,11 +137,13 @@ export const makeOrderCalculations = ({ : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() // always based, if is limit it can lead to a weird percentage - const priceDifference = priceWithFees - .minus(priceBase) - .dividedBy(priceBase) - .times(100) - .toString() + const priceDifference = Quantities.isZero(priceBase) + ? Quantities.zero + : priceWithFees + .minus(priceBase) + .dividedBy(priceBase) + .times(100) + .toString() return { priceWithFees: asQuantity(priceWithFees), @@ -146,17 +152,31 @@ export const makeOrderCalculations = ({ } } + // fees + ffee + slippage const { priceWithFees: withFees, priceWithFeesAndSlippage: withFeesAndSlippage, priceDifference: difference, - } = calculatePricesWithFees(true) + } = calculatePricesWithFees({withFrontendFee: true}) const { priceWithFees: withFeesNoFEF, priceWithFeesAndSlippage: withFeesAndSlippageNoFEF, priceDifference: differenceNoFEF, - } = calculatePricesWithFees(false) - return { + } = calculatePricesWithFees({withFrontendFee: false}) + + const result: SwapOrderCalculation = { + order: { + side, + slippage, + orderType, + limitPrice, + amounts, + lpTokenHeld, + }, + sides: { + buy, + sell, + }, cost: { batcherFee: pool.batcherFee, deposit: pool.deposit, @@ -177,6 +197,10 @@ export const makeOrderCalculations = ({ differenceNoFEF, }, pool, - } + } as const + + return result }) + + return calculations } diff --git a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx index 762dc31f25..194d232c82 100644 --- a/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx +++ b/packages/swap/src/translators/reactjs/provider/SwapProvider.tsx @@ -79,17 +79,11 @@ export const SwapProvider = ({ lpTokenHeldChanged: (amount: Balance.Amount | undefined) => { dispatch({type: SwapCreateOrderActionType.LpTokenHeldChanged, amount}) }, - buyTokenIdChanged: (payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - }) => { - dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, payload}) + buyTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { + dispatch({type: SwapCreateOrderActionType.BuyTokenIdChanged, tokenId}) }, - sellTokenIdChanged: (payload: { - tokenId: Balance.TokenInfo['id'] - pools: ReadonlyArray - }) => { - dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, payload}) + sellTokenIdChanged: (tokenId: Balance.TokenInfo['id']) => { + dispatch({type: SwapCreateOrderActionType.SellTokenIdChanged, tokenId}) }, poolPairsChanged: (pools: ReadonlyArray) => { dispatch({type: SwapCreateOrderActionType.PoolPairsChanged, pools}) From 2128dca3f060488ec4cb5c85112e4966dcc3d0b4 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Sun, 8 Oct 2023 23:49:31 +0100 Subject: [PATCH 60/67] chore: CR --- packages/swap/src/helpers/orders/makeOrderCalculations.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts index 648eb4fafc..8f555035ef 100644 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ b/packages/swap/src/helpers/orders/makeOrderCalculations.ts @@ -80,7 +80,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.sell.quantity) - .times(ptPriceSell) + .dividedBy(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -88,7 +88,7 @@ export const makeOrderCalculations = ({ tokenId: primaryTokenId, quantity: asQuantity( new BigNumber(amounts.buy.quantity) - .times(ptPriceBuy) + .dividedBy(ptPriceBuy) .integerValue(BigNumber.ROUND_CEIL), ), }, @@ -98,10 +98,10 @@ export const makeOrderCalculations = ({ // it applies market price always const feeInSellSideQuantities = { batcherFee: new BigNumber(pool.batcherFee.quantity) - .times(ptPriceSell) + .dividedBy(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .times(ptPriceSell) + .dividedBy(ptPriceSell) .integerValue(BigNumber.ROUND_CEIL), } From 9a1637c9455e042b22c9e1a6a9e5f666d7905946 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 01:35:31 +0100 Subject: [PATCH 61/67] wip: state --- .../SelectBuyTokenFromListScreen.tsx | 1 + .../Swap/common/AmountCard/AmountCard.json | 20 +++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 6ba130870f..0aedb824b4 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -190,6 +190,7 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { track.swapAssetToChanged({ to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], }) + buyTouched() buyTokenIdChanged(tokenForList.id) buyTouched() navigateTo.startSwap() diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index 7fa3933302..99bb074f3f 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -6,12 +6,12 @@ "start": { "line": 134, "column": 15, - "index": 4170 + "index": 4178 }, "end": { "line": 137, "column": 3, - "index": 4253 + "index": 4261 } }, { @@ -21,12 +21,12 @@ "start": { "line": 138, "column": 18, - "index": 4273 + "index": 4281 }, "end": { "line": 141, "column": 3, - "index": 4362 + "index": 4370 } }, { @@ -36,12 +36,12 @@ "start": { "line": 142, "column": 20, - "index": 4384 + "index": 4392 }, "end": { "line": 145, "column": 3, - "index": 4478 + "index": 4486 } }, { @@ -51,12 +51,12 @@ "start": { "line": 146, "column": 19, - "index": 4499 + "index": 4507 }, "end": { "line": 149, "column": 3, - "index": 4603 + "index": 4611 } }, { @@ -66,12 +66,12 @@ "start": { "line": 150, "column": 10, - "index": 4615 + "index": 4623 }, "end": { "line": 153, "column": 3, - "index": 4730 + "index": 4738 } } ] \ No newline at end of file From b82b8a321ee699ba22a8011993e3c4656aa7e282 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 09:20:22 +0100 Subject: [PATCH 62/67] wip: state --- .../EditBuyAmount/EditBuyAmount.tsx | 9 +++++++++ .../SelectBuyTokenFromListScreen.tsx | 1 - .../Swap/common/AmountCard/AmountCard.json | 20 +++++++++---------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx index ffc6414794..86d40e0d79 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx @@ -30,6 +30,15 @@ export const EditBuyAmount = () => { const [inputValue, setInputValue] = React.useState(Quantities.format(quantity, tokenInfo.decimals ?? 0)) React.useEffect(() => { + console.log('EditBuyAmount::useEffect') + console.log( + 'isBuyTouched', + isBuyTouched, + 'inputRef?.current?.isFocused()', + inputRef?.current?.isFocused(), + 'quantity', + quantity, + ) if (isBuyTouched && !inputRef?.current?.isFocused()) { setInputValue(Quantities.format(quantity, tokenInfo.decimals ?? 0)) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx index 0aedb824b4..6ba130870f 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/SelectBuyTokenFromListScreen/SelectBuyTokenFromListScreen.tsx @@ -190,7 +190,6 @@ const SelectableToken = ({tokenForList, wallet}: SelectableTokenProps) => { track.swapAssetToChanged({ to_asset: [{asset_name: tokenForList.name, asset_ticker: tokenForList.ticker, policy_id: tokenForList.group}], }) - buyTouched() buyTokenIdChanged(tokenForList.id) buyTouched() navigateTo.startSwap() diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index 99bb074f3f..7fa3933302 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -6,12 +6,12 @@ "start": { "line": 134, "column": 15, - "index": 4178 + "index": 4170 }, "end": { "line": 137, "column": 3, - "index": 4261 + "index": 4253 } }, { @@ -21,12 +21,12 @@ "start": { "line": 138, "column": 18, - "index": 4281 + "index": 4273 }, "end": { "line": 141, "column": 3, - "index": 4370 + "index": 4362 } }, { @@ -36,12 +36,12 @@ "start": { "line": 142, "column": 20, - "index": 4392 + "index": 4384 }, "end": { "line": 145, "column": 3, - "index": 4486 + "index": 4478 } }, { @@ -51,12 +51,12 @@ "start": { "line": 146, "column": 19, - "index": 4507 + "index": 4499 }, "end": { "line": 149, "column": 3, - "index": 4611 + "index": 4603 } }, { @@ -66,12 +66,12 @@ "start": { "line": 150, "column": 10, - "index": 4623 + "index": 4615 }, "end": { "line": 153, "column": 3, - "index": 4738 + "index": 4730 } } ] \ No newline at end of file From 6bc8a670ab2d22f9dec02411661e81611a964f44 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:26:40 +0100 Subject: [PATCH 63/67] wip: clean ups - get pt price --- .../orders/getLiquidityProviderFee.test.ts | 45 ---- .../helpers/orders/makeOrderCalculations.ts | 206 ------------------ 2 files changed, 251 deletions(-) delete mode 100644 packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts delete mode 100644 packages/swap/src/helpers/orders/makeOrderCalculations.ts diff --git a/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts b/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts deleted file mode 100644 index 63ccc03b78..0000000000 --- a/packages/swap/src/helpers/orders/getLiquidityProviderFee.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {Quantities} from '../../utils/quantities' -import {getLiquidityProviderFee} from './getLiquidityProviderFee' -import {asQuantity} from '../../utils/asQuantity' - -describe('getLiquidityProviderFee', () => { - it('should return zero when sell quantity is zero', () => { - const result = getLiquidityProviderFee('0.03', { - tokenId: 'testToken', - quantity: Quantities.zero, - }) - - expect(result).toEqual({ - tokenId: 'testToken', - quantity: Quantities.zero, - }) - }) - - it('should calculate provider fee correctly based on sell side', () => { - const expectedFee = '300' - - const result = getLiquidityProviderFee('0.03', { - tokenId: 'testToken', - quantity: '1000000', - }) - - expect(result).toEqual({ - tokenId: 'testToken', - quantity: asQuantity(expectedFee), - }) - }) - - it('should calculate fee ceil up', () => { - const expectedFee = '66' - - const result = getLiquidityProviderFee('66.666666', { - tokenId: 'testToken', - quantity: '99', - }) - - expect(result).toEqual({ - tokenId: 'testToken', - quantity: asQuantity(expectedFee), - }) - }) -}) diff --git a/packages/swap/src/helpers/orders/makeOrderCalculations.ts b/packages/swap/src/helpers/orders/makeOrderCalculations.ts deleted file mode 100644 index 8f555035ef..0000000000 --- a/packages/swap/src/helpers/orders/makeOrderCalculations.ts +++ /dev/null @@ -1,206 +0,0 @@ -import {Balance, Swap} from '@yoroi/types' -import {BigNumber} from 'bignumber.js' -import {SwapOrderCalculation} from '../../translators/reactjs/state/state' -import {getQuantityWithSlippage} from './getQuantityWithSlippage' -import {getLiquidityProviderFee} from './getLiquidityProviderFee' -import {getFrontendFee} from './getFrontendFee' -import {getMarketPrice} from './getMarketPrice' -import {getBuyAmount} from './getBuyAmount' -import {getSellAmount} from './getSellAmount' -import {asQuantity} from '../../utils/asQuantity' -import {Quantities} from '../../utils/quantities' - -export const makeOrderCalculations = ({ - orderType, - amounts, - limitPrice, - slippage, - pools, - primaryTokenId, - lpTokenHeld, - side, -}: Readonly<{ - orderType: Swap.OrderType - amounts: { - sell: Balance.Amount - buy: Balance.Amount - } - limitPrice?: Balance.Quantity - pools: ReadonlyArray - lpTokenHeld?: Balance.Amount - slippage: number - primaryTokenId: Balance.TokenInfo['id'] - side?: 'buy' | 'sell' -}>): Array => { - const isLimit = orderType === 'limit' - const maybeLimitPrice = isLimit ? limitPrice : undefined - - const calculations = pools.map((pool) => { - const buy = - side === 'sell' - ? getBuyAmount(pool, amounts.sell, maybeLimitPrice) - : amounts.buy - const sell = - side === 'buy' - ? getSellAmount(pool, amounts.buy, maybeLimitPrice) - : amounts.sell - - const marketPrice = getMarketPrice(pool, sell) - // recalculate price base, limit is user's input, market from pool - const priceBase = maybeLimitPrice ?? marketPrice - - // calculate buy quantity with slippage - const buyAmountWithSlippage: Balance.Amount = { - quantity: getQuantityWithSlippage(buy.quantity, slippage), - tokenId: buy.tokenId, - } - - // pools that with not enough supply will be filtered out - const isBuyTokenA = buy.tokenId === pool.tokenA.tokenId - const poolSupply = isBuyTokenA ? pool.tokenA.quantity : pool.tokenB.quantity - const hasSupply = !Quantities.isGreaterThan( - buy.quantity, - poolSupply ?? Quantities.zero, - ) - - // lf is sell side % of quantity ie. XToken 100 * 1% = 1 XToken - const liquidityFee: Balance.Amount = getLiquidityProviderFee(pool.fee, sell) - - const [ptPriceBuy, ptPriceSell] = isBuyTokenA - ? [pool.ptPriceTokenA, pool.ptPriceTokenB] - : [pool.ptPriceTokenB, pool.ptPriceTokenA] - - // ffee is based on PT value range + LP holding range (sides may need conversion, when none is PT) - const frontendFeeInfo = getFrontendFee({ - sell, - buy, - lpTokenHeld, - primaryTokenId, - sellInPrimaryTokenValue: { - tokenId: primaryTokenId, - quantity: asQuantity( - new BigNumber(amounts.sell.quantity) - .dividedBy(ptPriceSell) - .integerValue(BigNumber.ROUND_CEIL), - ), - }, - buyInPrimaryTokenValue: { - tokenId: primaryTokenId, - quantity: asQuantity( - new BigNumber(amounts.buy.quantity) - .dividedBy(ptPriceBuy) - .integerValue(BigNumber.ROUND_CEIL), - ), - }, - }) - - // transform fees in terms of sell side quantity * pt price (unit of fees) - // it applies market price always - const feeInSellSideQuantities = { - batcherFee: new BigNumber(pool.batcherFee.quantity) - .dividedBy(ptPriceSell) - .integerValue(BigNumber.ROUND_CEIL), - frontendFee: new BigNumber(frontendFeeInfo.fee.quantity) - .dividedBy(ptPriceSell) - .integerValue(BigNumber.ROUND_CEIL), - } - - const priceWithSlippage = Quantities.isZero(buyAmountWithSlippage.quantity) - ? Quantities.zero - : asQuantity( - new BigNumber(sell.quantity) - .dividedBy(buyAmountWithSlippage.quantity) - .toString(), - ) - - const calculatePricesWithFees = ({ - withFrontendFee, - }: { - withFrontendFee?: boolean - }) => { - // add up all that's being sold in sell terms - const sellWithBatcher = new BigNumber(sell.quantity).plus( - feeInSellSideQuantities.batcherFee, - ) - const sellWithFees = withFrontendFee - ? sellWithBatcher.plus(feeInSellSideQuantities.frontendFee) - : sellWithBatcher - - const priceWithFees = Quantities.isZero(buy.quantity) - ? new BigNumber(0) - : sellWithFees.dividedBy(buy.quantity) - - const priceWithFeesAndSlippage = Quantities.isZero( - buyAmountWithSlippage.quantity, - ) - ? Quantities.zero - : sellWithFees.dividedBy(buyAmountWithSlippage.quantity).toString() - - // always based, if is limit it can lead to a weird percentage - const priceDifference = Quantities.isZero(priceBase) - ? Quantities.zero - : priceWithFees - .minus(priceBase) - .dividedBy(priceBase) - .times(100) - .toString() - - return { - priceWithFees: asQuantity(priceWithFees), - priceWithFeesAndSlippage: asQuantity(priceWithFeesAndSlippage), - priceDifference: asQuantity(priceDifference), - } - } - - // fees + ffee + slippage - const { - priceWithFees: withFees, - priceWithFeesAndSlippage: withFeesAndSlippage, - priceDifference: difference, - } = calculatePricesWithFees({withFrontendFee: true}) - const { - priceWithFees: withFeesNoFEF, - priceWithFeesAndSlippage: withFeesAndSlippageNoFEF, - priceDifference: differenceNoFEF, - } = calculatePricesWithFees({withFrontendFee: false}) - - const result: SwapOrderCalculation = { - order: { - side, - slippage, - orderType, - limitPrice, - amounts, - lpTokenHeld, - }, - sides: { - buy, - sell, - }, - cost: { - batcherFee: pool.batcherFee, - deposit: pool.deposit, - frontendFeeInfo, - liquidityFee, - }, - buyAmountWithSlippage, - hasSupply, - prices: { - base: priceBase, - market: marketPrice, - withSlippage: priceWithSlippage, - withFees, - withFeesAndSlippage, - difference, - withFeesNoFEF, - withFeesAndSlippageNoFEF, - differenceNoFEF, - }, - pool, - } as const - - return result - }) - - return calculations -} From 0cc95b01b4d9b3cd958210f6cee32fafa94a9363 Mon Sep 17 00:00:00 2001 From: Juliano Lazzarotto <30806844+stackchain@users.noreply.github.com> Date: Mon, 9 Oct 2023 19:38:57 +0100 Subject: [PATCH 64/67] chore: state and behaviors --- .../CreateOrder/EditBuyAmount/EditBuyAmount.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx index 86d40e0d79..ffc6414794 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditBuyAmount/EditBuyAmount.tsx @@ -30,15 +30,6 @@ export const EditBuyAmount = () => { const [inputValue, setInputValue] = React.useState(Quantities.format(quantity, tokenInfo.decimals ?? 0)) React.useEffect(() => { - console.log('EditBuyAmount::useEffect') - console.log( - 'isBuyTouched', - isBuyTouched, - 'inputRef?.current?.isFocused()', - inputRef?.current?.isFocused(), - 'quantity', - quantity, - ) if (isBuyTouched && !inputRef?.current?.isFocused()) { setInputValue(Quantities.format(quantity, tokenInfo.decimals ?? 0)) } From 7d435446cd10eed497f7010113d0df33a22ea1b6 Mon Sep 17 00:00:00 2001 From: Ruslan Dudin Date: Tue, 10 Oct 2023 12:57:14 +0300 Subject: [PATCH 65/67] New Crowdin updates (#2747) --- apps/wallet-mobile/src/i18n/locales/bn-BD.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/cs-CZ.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/de-DE.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/el-GR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/fil-PH.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/fr-FR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/hr-HR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/hu-HU.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/id-ID.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/it-IT.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/ja-JP.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/ko-KR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/nl-NL.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/pl-PL.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/pt-BR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/ru-RU.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sk-SK.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sl-SI.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sv-SE.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/sw-KE.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/tr-TR.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/uk-UA.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/vi-VN.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/zh-Hans.json | 6 ++++-- apps/wallet-mobile/src/i18n/locales/zh-Hant.json | 6 ++++-- 25 files changed, 100 insertions(+), 50 deletions(-) diff --git a/apps/wallet-mobile/src/i18n/locales/bn-BD.json b/apps/wallet-mobile/src/i18n/locales/bn-BD.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/bn-BD.json +++ b/apps/wallet-mobile/src/i18n/locales/bn-BD.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/cs-CZ.json b/apps/wallet-mobile/src/i18n/locales/cs-CZ.json index 00bdf73fb2..32749fa7f8 100644 --- a/apps/wallet-mobile/src/i18n/locales/cs-CZ.json +++ b/apps/wallet-mobile/src/i18n/locales/cs-CZ.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/de-DE.json b/apps/wallet-mobile/src/i18n/locales/de-DE.json index 586a65f2aa..bdb1c503a1 100644 --- a/apps/wallet-mobile/src/i18n/locales/de-DE.json +++ b/apps/wallet-mobile/src/i18n/locales/de-DE.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/el-GR.json b/apps/wallet-mobile/src/i18n/locales/el-GR.json index 1ee34cdd35..ed0b3f1de2 100644 --- a/apps/wallet-mobile/src/i18n/locales/el-GR.json +++ b/apps/wallet-mobile/src/i18n/locales/el-GR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/fil-PH.json b/apps/wallet-mobile/src/i18n/locales/fil-PH.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/fil-PH.json +++ b/apps/wallet-mobile/src/i18n/locales/fil-PH.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/fr-FR.json b/apps/wallet-mobile/src/i18n/locales/fr-FR.json index d06349396c..a68ac857af 100644 --- a/apps/wallet-mobile/src/i18n/locales/fr-FR.json +++ b/apps/wallet-mobile/src/i18n/locales/fr-FR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "auto", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": "Valeur totale verrouillée", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "Ordres complétés", "swap.listOrders.open": "Ordres en cours", "swap.listOrders.sheet.title": "Confirmer l'annulation de l'ordre", diff --git a/apps/wallet-mobile/src/i18n/locales/hr-HR.json b/apps/wallet-mobile/src/i18n/locales/hr-HR.json index f78273303a..d281577526 100644 --- a/apps/wallet-mobile/src/i18n/locales/hr-HR.json +++ b/apps/wallet-mobile/src/i18n/locales/hr-HR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/hu-HU.json b/apps/wallet-mobile/src/i18n/locales/hu-HU.json index efb4c99cf6..e8993bce85 100644 --- a/apps/wallet-mobile/src/i18n/locales/hu-HU.json +++ b/apps/wallet-mobile/src/i18n/locales/hu-HU.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/id-ID.json b/apps/wallet-mobile/src/i18n/locales/id-ID.json index 21c5e54500..26602664c1 100644 --- a/apps/wallet-mobile/src/i18n/locales/id-ID.json +++ b/apps/wallet-mobile/src/i18n/locales/id-ID.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/it-IT.json b/apps/wallet-mobile/src/i18n/locales/it-IT.json index cc138280ec..c6eb4c94f3 100644 --- a/apps/wallet-mobile/src/i18n/locales/it-IT.json +++ b/apps/wallet-mobile/src/i18n/locales/it-IT.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/ja-JP.json b/apps/wallet-mobile/src/i18n/locales/ja-JP.json index ebc33e9621..a5505a7232 100644 --- a/apps/wallet-mobile/src/i18n/locales/ja-JP.json +++ b/apps/wallet-mobile/src/i18n/locales/ja-JP.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/ko-KR.json b/apps/wallet-mobile/src/i18n/locales/ko-KR.json index 1cc2fd9656..afebaf2d5e 100644 --- a/apps/wallet-mobile/src/i18n/locales/ko-KR.json +++ b/apps/wallet-mobile/src/i18n/locales/ko-KR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/nl-NL.json b/apps/wallet-mobile/src/i18n/locales/nl-NL.json index b2847e097c..2b3840d78a 100644 --- a/apps/wallet-mobile/src/i18n/locales/nl-NL.json +++ b/apps/wallet-mobile/src/i18n/locales/nl-NL.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/pl-PL.json b/apps/wallet-mobile/src/i18n/locales/pl-PL.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/pl-PL.json +++ b/apps/wallet-mobile/src/i18n/locales/pl-PL.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/pt-BR.json b/apps/wallet-mobile/src/i18n/locales/pt-BR.json index 0351dc5bc4..5304d656da 100644 --- a/apps/wallet-mobile/src/i18n/locales/pt-BR.json +++ b/apps/wallet-mobile/src/i18n/locales/pt-BR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Mínimo", - "swap.swapScreen.swapFees": "As taxas da operação incluem:\n • Taxa do executor das ordens\n • Taxa da carteira\n • Taxa do operador da reserva", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Mín. a ser recebido", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": "VTA", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/ru-RU.json b/apps/wallet-mobile/src/i18n/locales/ru-RU.json index dda3deaad3..1c48e28b1d 100644 --- a/apps/wallet-mobile/src/i18n/locales/ru-RU.json +++ b/apps/wallet-mobile/src/i18n/locales/ru-RU.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(авто)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sk-SK.json b/apps/wallet-mobile/src/i18n/locales/sk-SK.json index 61d9f17618..d98854a9bb 100644 --- a/apps/wallet-mobile/src/i18n/locales/sk-SK.json +++ b/apps/wallet-mobile/src/i18n/locales/sk-SK.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sl-SI.json b/apps/wallet-mobile/src/i18n/locales/sl-SI.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/sl-SI.json +++ b/apps/wallet-mobile/src/i18n/locales/sl-SI.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sv-SE.json b/apps/wallet-mobile/src/i18n/locales/sv-SE.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/sv-SE.json +++ b/apps/wallet-mobile/src/i18n/locales/sv-SE.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/sw-KE.json b/apps/wallet-mobile/src/i18n/locales/sw-KE.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/sw-KE.json +++ b/apps/wallet-mobile/src/i18n/locales/sw-KE.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/tr-TR.json b/apps/wallet-mobile/src/i18n/locales/tr-TR.json index 1acda6a62c..fe47afa2a7 100644 --- a/apps/wallet-mobile/src/i18n/locales/tr-TR.json +++ b/apps/wallet-mobile/src/i18n/locales/tr-TR.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/uk-UA.json b/apps/wallet-mobile/src/i18n/locales/uk-UA.json index e198faa504..6d8692775d 100644 --- a/apps/wallet-mobile/src/i18n/locales/uk-UA.json +++ b/apps/wallet-mobile/src/i18n/locales/uk-UA.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/vi-VN.json b/apps/wallet-mobile/src/i18n/locales/vi-VN.json index aaf22662b0..0fd161995b 100644 --- a/apps/wallet-mobile/src/i18n/locales/vi-VN.json +++ b/apps/wallet-mobile/src/i18n/locales/vi-VN.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/zh-Hans.json b/apps/wallet-mobile/src/i18n/locales/zh-Hans.json index b453229383..fcacf61595 100644 --- a/apps/wallet-mobile/src/i18n/locales/zh-Hans.json +++ b/apps/wallet-mobile/src/i18n/locales/zh-Hans.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", diff --git a/apps/wallet-mobile/src/i18n/locales/zh-Hant.json b/apps/wallet-mobile/src/i18n/locales/zh-Hant.json index cb8208a273..410f67bafa 100644 --- a/apps/wallet-mobile/src/i18n/locales/zh-Hant.json +++ b/apps/wallet-mobile/src/i18n/locales/zh-Hant.json @@ -157,16 +157,18 @@ "swap.swapScreen.defaultSlippage": "Default Slippage Tolerance", "swap.swapScreen.slippageInfo": "Slippage tolerance is set as a percentage of the total swap value. Your transactions will not be executed if the price moves by more than this amount.", "swap.swapScreen.autoPool": "(auto)", + "swap.swapScreen.changePool": "change pool", "swap.swapScreen.swapMinAda": "Min-ADA is the minimum ADA amount required to be contained when holding or sending Cardano native tokens.", "swap.swapScreen.swapMinAdaTitle": "Min ADA", - "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee\n • Liquidity Provider Fee", + "swap.swapScreen.swapFees": "Swap fees include the following:\n • Matchmaker Fee\n • Frontend Fee", "swap.swapScreen.swapFeesTitle": "Fees", + "swap.swapScreen.swapLiquidityFee": "Liquidity provider fee ({fee}%)", "swap.swapScreen.swapMinReceived": "Minimum amount of tokens you can get because of the slippage tolerance.", "swap.swapScreen.swapMinReceivedTitle": "Min Received", "swap.swapScreen.enterSlippage": "Enter a value from 0% to 100%. You can also enter up to 1 decimal", "swap.swapScreen.poolVerification": "{pool} verification", "swap.swapScreen.volume": "Volume, 24h", - "swap.swapScreen.tvl": " TVL", + "swap.swapScreen.tvl": "TVL", "swap.listOrders.completed": "completed orders", "swap.listOrders.open": "open orders", "swap.listOrders.sheet.title": "Confirm order cancelation", From 98c147b93bed49fe82eb9651c96558bfadc8ba1e Mon Sep 17 00:00:00 2001 From: jorbuedo Date: Tue, 10 Oct 2023 13:05:48 +0200 Subject: [PATCH 66/67] Min received with slippage --- .../ConfirmTxScreen/TransactionSummary.tsx | 10 ++---- .../CreateOrder/EditPool/ShowPoolActions.tsx | 10 ++---- .../getMinAdaReceiveAfterSlippage.test.ts | 34 ------------------- .../amounts/getMinAdaReceiveAfterSlippage.ts | 30 ---------------- packages/swap/src/index.ts | 1 - 5 files changed, 6 insertions(+), 79 deletions(-) delete mode 100644 packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts delete mode 100644 packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts diff --git a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx index 8200a426d9..04612bbb6f 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/ConfirmTxScreen/TransactionSummary.tsx @@ -1,11 +1,10 @@ -import {getMinAdaReceiveAfterSlippage, useSwap} from '@yoroi/swap' +import {useSwap} from '@yoroi/swap' import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {Icon, Spacer, Text} from '../../../../components' import {AmountItem} from '../../../../components/AmountItem/AmountItem' import {BottomSheetModal} from '../../../../components/BottomSheetModal' -import {useLanguage} from '../../../../i18n' import {useSelectedWallet} from '../../../../SelectedWallet' import {COLORS} from '../../../../theme' import {useTokenInfo} from '../../../../yoroi-wallets/hooks' @@ -20,7 +19,6 @@ export const TransactionSummary = () => { }) const strings = useStrings() const wallet = useSelectedWallet() - const {numberLocale} = useLanguage() const {orderData} = useSwap() const {amounts, selectedPoolCalculation} = orderData @@ -39,11 +37,9 @@ export const TransactionSummary = () => { }, { label: strings.swapMinReceivedTitle, - value: `${getMinAdaReceiveAfterSlippage( - amounts.buy.quantity, - orderData.slippage, + value: `${Quantities.format( + selectedPoolCalculation?.buyAmountWithSlippage?.quantity ?? Quantities.zero, buyTokenInfo.decimals ?? 0, - numberLocale, )} ${tokenToBuyName}`, info: strings.swapMinReceived, }, diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx index 9a15564560..ddc9f35c62 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditPool/ShowPoolActions.tsx @@ -1,4 +1,4 @@ -import {getMinAdaReceiveAfterSlippage, useSwap} from '@yoroi/swap' +import {useSwap} from '@yoroi/swap' import {capitalize} from 'lodash' import React from 'react' import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' @@ -10,7 +10,6 @@ import { HiddenInfoWrapper, Spacer, } from '../../../../../../components' -import {useLanguage} from '../../../../../../i18n' import {useSelectedWallet} from '../../../../../../SelectedWallet' import {COLORS} from '../../../../../../theme' import {useTokenInfo} from '../../../../../../yoroi-wallets/hooks' @@ -22,7 +21,6 @@ import {useSwapTouched} from '../../../../common/SwapFormProvider' export const ShowPoolActions = () => { const navigateTo = useNavigateTo() - const {numberLocale} = useLanguage() const {orderData} = useSwap() const strings = useStrings() const {isBuyTouched, isSellTouched, isPoolTouched} = useSwapTouched() @@ -90,11 +88,9 @@ export const ShowPoolActions = () => { selectedPoolCalculation.pool.batcherFee.quantity, Number(wallet.primaryTokenInfo.decimals), )} - minReceived={getMinAdaReceiveAfterSlippage( - amounts.buy.quantity, - orderData.slippage, + minReceived={Quantities.format( + selectedPoolCalculation.buyAmountWithSlippage.quantity, buyTokenInfo.decimals ?? 0, - numberLocale, )} minAda={Quantities.format( selectedPoolCalculation.pool.deposit.quantity, diff --git a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts deleted file mode 100644 index d0ac842251..0000000000 --- a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {mockNumberLocale} from '../../../adapters/intl/number-locale.mocks' -import {asQuantity} from '../../../utils/asQuantity' -import {getMinAdaReceiveAfterSlippage} from './getMinAdaReceiveAfterSlippage' - -describe('getMinAdaReceiveAfterSlippage', () => { - it('should calculate the correct minimum ADA received after applying slippage', () => { - expect( - getMinAdaReceiveAfterSlippage( - asQuantity(1000), - 0.03, - 2, - mockNumberLocale, - ), - ).toBe('9.9') - expect( - getMinAdaReceiveAfterSlippage(asQuantity(500), 1, 2, mockNumberLocale), - ).toBe('4.9') - expect( - getMinAdaReceiveAfterSlippage(asQuantity(1000), 2, 2, mockNumberLocale), - ).toBe('9.8') - }) - - it('should return the original amount when slippage is zero', () => { - expect( - getMinAdaReceiveAfterSlippage(asQuantity(1000), 0, 2, mockNumberLocale), - ).toBe('1') - }) - - it('should return zero when the output amount is zero', () => { - expect( - getMinAdaReceiveAfterSlippage(asQuantity(0), 5, 2, mockNumberLocale), - ).toBe('') - }) -}) diff --git a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts b/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts deleted file mode 100644 index 828abc1b15..0000000000 --- a/packages/swap/src/helpers/orders/amounts/getMinAdaReceiveAfterSlippage.ts +++ /dev/null @@ -1,30 +0,0 @@ -import {Balance, Numbers} from '@yoroi/types' -import {Quantities} from '../../../utils/quantities' -import {asQuantity} from '../../../utils/asQuantity' - -/** - * Calculate the minimum amount of ADA received after accounting for slippage. - * - * @param {Balance.Quantity} outputAmount - The amount of ADA or output currency. - * @param {number} slippagePercentage - The slippage percentage as a decimal (e.g., 3% as 0.03). - * @param {number} decimals - The number of decimal places for formatting the result. - * @param {NumberLocale} numberLocale - The locale information for formatting numbers. - * - * @returns {string} The minimum ADA amount received after slippage as a string with specified decimals. - */ - -export const getMinAdaReceiveAfterSlippage = ( - outputAmount: Balance.Quantity, - slippagePercentage: number, - decimals: number, - numberLocale: Numbers.Locale, -): string => { - const slippageDecimal = slippagePercentage / 100 - const result = Number(outputAmount) / (1 + slippageDecimal) - const [quantities] = Quantities.parseFromText( - Quantities.denominated(asQuantity(result), decimals), - decimals, - numberLocale, - ) - return quantities.slice(0, -1) -} diff --git a/packages/swap/src/index.ts b/packages/swap/src/index.ts index 91d86d1005..c6cb65ddcd 100644 --- a/packages/swap/src/index.ts +++ b/packages/swap/src/index.ts @@ -10,7 +10,6 @@ export {apiMocks} from './adapters/openswap-api/api.mocks' // orders amounts export {getBuyAmount} from './helpers/orders/amounts/getBuyAmount' export {getSellAmount} from './helpers/orders/amounts/getSellAmount' -export {getMinAdaReceiveAfterSlippage} from './helpers/orders/amounts/getMinAdaReceiveAfterSlippage' export {getQuantityWithSlippage} from './helpers/orders/amounts/getQuantityWithSlippage' // orders factories export {makePossibleMarketOrder} from './helpers/orders/factories/makePossibleMarketOrder' From 043b8b6b0fb49cd4d48398c12cbe369cd41a40a1 Mon Sep 17 00:00:00 2001 From: Sorin Chis Date: Tue, 10 Oct 2023 14:22:02 +0300 Subject: [PATCH 67/67] fix: edit limit price (#2748) --- .../CreateOrder/EditLimitPrice.tsx | 10 +++-- .../ShowTokenActions/ClearQuantities.tsx | 3 +- .../ShowTokenActions/TopTokenActions.tsx | 3 +- .../Swap/common/AmountCard/AmountCard.json | 40 +++++++++---------- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx index 53d342cf13..74ae20f445 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/EditLimitPrice.tsx @@ -19,6 +19,7 @@ export const EditLimitPrice = () => { const {numberLocale} = useLanguage() const [text, setText] = React.useState('') const wallet = useSelectedWallet() + const inputRef = React.useRef(null) const {orderData, limitPriceChanged} = useSwap() const sellTokenInfo = useTokenInfo({wallet, tokenId: orderData.amounts.sell.tokenId}) @@ -33,7 +34,8 @@ export const EditLimitPrice = () => { React.useEffect(() => { if (orderData.type === 'limit') { - setText(Quantities.format(orderData.limitPrice ?? Quantities.zero, denomination, PRECISION)) + !inputRef?.current?.isFocused() && + setText(Quantities.format(orderData.limitPrice ?? Quantities.zero, denomination, PRECISION)) } else { setText( Quantities.format(orderData.selectedPoolCalculation?.prices.market ?? Quantities.zero, denomination, PRECISION), @@ -54,7 +56,7 @@ export const EditLimitPrice = () => { {disabled ? strings.marketPrice : strings.limitPrice} - + @@ -70,8 +72,9 @@ type AmountInputProps = { value?: string onChange(value: string): void editable: boolean + inputRef?: React.RefObject } -const AmountInput = ({onChange, value, editable}: AmountInputProps) => { +const AmountInput = ({onChange, value, editable, inputRef}: AmountInputProps) => { return ( { style={styles.amountInput} underlineColorAndroid="transparent" editable={editable} + ref={inputRef} /> ) } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx index 28c49f79e6..a5873c84c6 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/ClearQuantities.tsx @@ -1,6 +1,6 @@ import {useSwap} from '@yoroi/swap' import React from 'react' -import {StyleSheet, Text} from 'react-native' +import {Keyboard, StyleSheet, Text} from 'react-native' import {TouchableOpacity} from 'react-native-gesture-handler' import {COLORS} from '../../../../../../theme' @@ -13,6 +13,7 @@ export const ClearQuantities = () => { const {poolDefaulted} = useSwapTouched() const handleReset = () => { + Keyboard.dismiss() resetQuantities() poolDefaulted() } diff --git a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx index 561123cbc4..d60ef48368 100644 --- a/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx +++ b/apps/wallet-mobile/src/features/Swap/useCases/StartSwapScreen/CreateOrder/ShowTokenActions/TopTokenActions.tsx @@ -1,6 +1,6 @@ import {useSwap, useSwapPoolsByPair} from '@yoroi/swap' import React from 'react' -import {StyleSheet, View} from 'react-native' +import {Keyboard, StyleSheet, View} from 'react-native' import {TouchableOpacity} from 'react-native-gesture-handler' import {Icon} from '../../../../../../components' @@ -40,6 +40,7 @@ export const TopTokenActions = () => { } const handleRefresh = () => { + Keyboard.dismiss() refetch() } diff --git a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json index 7fa3933302..51c7130421 100644 --- a/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json +++ b/apps/wallet-mobile/translations/messages/src/features/Swap/common/AmountCard/AmountCard.json @@ -4,14 +4,14 @@ "defaultMessage": "!!!Select token", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 134, + "line": 135, "column": 15, - "index": 4170 + "index": 4171 }, "end": { - "line": 137, + "line": 138, "column": 3, - "index": 4253 + "index": 4254 } }, { @@ -19,14 +19,14 @@ "defaultMessage": "!!!Current Balance", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 138, + "line": 139, "column": 18, - "index": 4273 + "index": 4274 }, "end": { - "line": 141, + "line": 142, "column": 3, - "index": 4362 + "index": 4363 } }, { @@ -34,14 +34,14 @@ "defaultMessage": "!!!Not enough balance", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 142, + "line": 143, "column": 20, - "index": 4384 + "index": 4385 }, "end": { - "line": 145, + "line": 146, "column": 3, - "index": 4478 + "index": 4479 } }, { @@ -49,14 +49,14 @@ "defaultMessage": "!!!Not enough supply in the pool", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 146, + "line": 147, "column": 19, - "index": 4499 + "index": 4500 }, "end": { - "line": 149, + "line": 150, "column": 3, - "index": 4603 + "index": 4604 } }, { @@ -64,14 +64,14 @@ "defaultMessage": "!!! This pair is not available in any liquidity pool", "file": "src/features/Swap/common/AmountCard/AmountCard.tsx", "start": { - "line": 150, + "line": 151, "column": 10, - "index": 4615 + "index": 4616 }, "end": { - "line": 153, + "line": 154, "column": 3, - "index": 4730 + "index": 4731 } } ] \ No newline at end of file