Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: trade ratio & CoW quote display #5062

Original file line number Diff line number Diff line change
Expand Up @@ -302,11 +302,11 @@ const FirstHop = ({
const {
buyAsset,
sellAsset,
sellAmountBeforeFeesCryptoBaseUnit,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
buyAmountBeforeFeesCryptoBaseUnit,
} = tradeQuoteStep
const sellAmountCryptoPrecision = fromBaseUnit(
sellAmountBeforeFeesCryptoBaseUnit,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
sellAsset.precision,
)
const buyAmountCryptoPrecision = fromBaseUnit(
Expand Down Expand Up @@ -472,11 +472,11 @@ const SecondHop = ({
const {
buyAsset,
sellAsset,
sellAmountBeforeFeesCryptoBaseUnit,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
buyAmountBeforeFeesCryptoBaseUnit,
} = tradeQuoteStep
const sellAmountCryptoPrecision = fromBaseUnit(
sellAmountBeforeFeesCryptoBaseUnit,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
sellAsset.precision,
)
const buyAmountCryptoPrecision = fromBaseUnit(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { bnOrZero } from 'lib/bignumber/bignumber'
import { fromBaseUnit } from 'lib/math'
import type { AmountDisplayMeta, ProtocolFee } from 'lib/swapper/api'
import { SwapperName } from 'lib/swapper/api'
import type { PartialRecord } from 'lib/utils'
import { isSome } from 'lib/utils'

type ReceiveSummaryProps = {
isLoading?: boolean
Expand All @@ -27,7 +29,7 @@ type ReceiveSummaryProps = {
intermediaryTransactionOutputs?: AmountDisplayMeta[]
fiatAmount?: string
amountBeforeFeesCryptoPrecision?: string
protocolFees?: Record<AssetId, ProtocolFee>
protocolFees?: PartialRecord<AssetId, ProtocolFee>
shapeShiftFee?: string
slippage: string
swapperName: string
Expand Down Expand Up @@ -72,7 +74,10 @@ export const ReceiveSummary: FC<ReceiveSummaryProps> = memo(
}, [])

const protocolFeesParsed = useMemo(
() => (protocolFees ? parseAmountDisplayMeta(Object.values(protocolFees)) : undefined),
() =>
protocolFees
? parseAmountDisplayMeta(Object.values(protocolFees).filter(isSome))
: undefined,
[protocolFees, parseAmountDisplayMeta],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ import {
selectFirstHopSellFeeAsset,
selectLastHop,
selectLastHopBuyAsset,
selectNetBuyAmountCryptoPrecision,
selectNetBuyAmountUserCurrency,
selectNetReceiveAmountCryptoPrecision,
selectQuoteDonationAmountUserCurrency,
selectReceiveBuyAmountUserCurrency,
selectSellAmountBeforeFeesCryptoPrecision,
selectSellAmountUserCurrency,
selectTotalNetworkFeeUserCurrencyPrecision,
Expand Down Expand Up @@ -125,9 +125,9 @@ export const TradeConfirm = () => {
const lastStep = useAppSelector(selectLastHop)
const swapperName = useAppSelector(selectActiveSwapperName)
const defaultFeeAsset = useAppSelector(selectFirstHopSellFeeAsset)
const netBuyAmountCryptoPrecision = useAppSelector(selectNetBuyAmountCryptoPrecision)
const buyAmountAfterFeesCryptoPrecision = useAppSelector(selectNetReceiveAmountCryptoPrecision)
const slippageDecimal = useAppSelector(selectTradeSlippagePercentageDecimal)
const netBuyAmountUserCurrency = useAppSelector(selectNetBuyAmountUserCurrency)
const netBuyAmountUserCurrency = useAppSelector(selectReceiveBuyAmountUserCurrency)
const buyAmountBeforeFeesUserCurrency = useAppSelector(selectBuyAmountBeforeFeesUserCurrency)
const sellAmountBeforeFeesUserCurrency = useAppSelector(selectSellAmountUserCurrency)
const networkFeeCryptoHuman = useAppSelector(selectFirstHopNetworkFeeCryptoPrecision)
Expand Down Expand Up @@ -365,7 +365,7 @@ export const TradeConfirm = () => {
</Row>
<ReceiveSummary
symbol={buyAsset?.symbol ?? ''}
amountCryptoPrecision={netBuyAmountCryptoPrecision ?? ''}
amountCryptoPrecision={buyAmountAfterFeesCryptoPrecision ?? ''}
amountBeforeFeesCryptoPrecision={buyAmountBeforeFeesCryptoPrecision ?? ''}
protocolFees={tradeQuoteStep?.feeData.protocolFees}
shapeShiftFee='0'
Expand All @@ -383,7 +383,7 @@ export const TradeConfirm = () => {
sellAsset?.symbol,
sellAmountBeforeFeesUserCurrency,
buyAsset?.symbol,
netBuyAmountCryptoPrecision,
buyAmountAfterFeesCryptoPrecision,
buyAmountBeforeFeesCryptoPrecision,
tradeQuoteStep?.feeData.protocolFees,
tradeQuoteStep?.intermediaryTransactionOutputs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ import {
selectBuyAmountBeforeFeesCryptoPrecision,
selectBuyAmountBeforeFeesUserCurrency,
selectFirstHop,
selectNetBuyAmountUserCurrency,
selectNetReceiveAmountCryptoPrecision,
selectReceiveBuyAmountUserCurrency,
selectSellAmountUserCurrency,
selectSwapperSupportsCrossAccountTrade,
selectTotalNetworkFeeUserCurrencyPrecision,
Expand Down Expand Up @@ -105,7 +105,7 @@ export const TradeInput = memo(() => {
const totalProtocolFees = useAppSelector(selectTotalProtocolFeeByAsset)
const buyAmountAfterFeesCryptoPrecision = useAppSelector(selectNetReceiveAmountCryptoPrecision)
const buyAmountBeforeFeesUserCurrency = useAppSelector(selectBuyAmountBeforeFeesUserCurrency)
const buyAmountAfterFeesUserCurrency = useAppSelector(selectNetBuyAmountUserCurrency)
const buyAmountAfterFeesUserCurrency = useAppSelector(selectReceiveBuyAmountUserCurrency)
const totalNetworkFeeFiatPrecision = useAppSelector(selectTotalNetworkFeeUserCurrencyPrecision)
const manualReceiveAddressIsValidating = useAppSelector(selectManualReceiveAddressIsValidating)
const sellAmountCryptoPrecision = useAppSelector(selectSellAmountCryptoPrecision)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export const checkApprovalNeeded = async (
chainId: sellAsset.chainId,
})

return bn(allowanceOnChainCryptoBaseUnit).lt(tradeQuoteStep.sellAmountBeforeFeesCryptoBaseUnit)
return bn(allowanceOnChainCryptoBaseUnit).lt(
tradeQuoteStep.sellAmountIncludingProtocolFeesCryptoBaseUnit,
)
}

export const getApprovalTxData = async (
Expand All @@ -47,7 +49,7 @@ export const getApprovalTxData = async (
isExactAllowance: boolean,
): Promise<{ buildCustomTxInput: evm.BuildCustomTxInput; networkFeeCryptoBaseUnit: string }> => {
const approvalAmountCryptoBaseUnit = isExactAllowance
? tradeQuoteStep.sellAmountBeforeFeesCryptoBaseUnit
? tradeQuoteStep.sellAmountIncludingProtocolFeesCryptoBaseUnit
: MAX_ALLOWANCE

const { assetReference } = fromAssetId(tradeQuoteStep.sellAsset.assetId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const getTradeQuoteArgs = async ({
}: GetTradeQuoteInputArgs): Promise<GetTradeQuoteInput | undefined> => {
if (!sellAsset || !buyAsset) return undefined
const tradeQuoteInputCommonArgs: TradeQuoteInputCommonArgs = {
sellAmountBeforeFeesCryptoBaseUnit: toBaseUnit(
sellAmountIncludingProtocolFeesCryptoBaseUnit: toBaseUnit(
sellAmountBeforeFeesCryptoPrecision,
sellAsset?.precision || 0,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type GetMixPanelDataFromApiQuotesReturn = {
sellAssetId: string | undefined
buyAssetId: string | undefined
sellAmountUsd: string | undefined
version: string // ISO 8601 standard basic format date
}

const getMixPanelDataFromApiQuotes = (quotes: ApiQuote[]): GetMixPanelDataFromApiQuotesReturn => {
Expand All @@ -62,7 +63,10 @@ const getMixPanelDataFromApiQuotes = (quotes: ApiQuote[]): GetMixPanelDataFromAp
})
.filter(isSome)

return { quoteMeta, sellAssetId, buyAssetId, sellAmountUsd }
// Add a version string, in the form of an ISO 8601 standard basic format date, to the JSON blob to help with reporting
const version = '20230823'
0xApotheosis marked this conversation as resolved.
Show resolved Hide resolved

return { quoteMeta, sellAssetId, buyAssetId, sellAmountUsd, version }
}

const isEqualExceptAffiliateBpsAndSlippage = (
Expand Down
2 changes: 1 addition & 1 deletion src/components/MultiHopTrade/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export type GetReceiveAddressArgs = {

export type TradeQuoteInputCommonArgs = Pick<
GetTradeQuoteInput,
| 'sellAmountBeforeFeesCryptoBaseUnit'
| 'sellAmountIncludingProtocolFeesCryptoBaseUnit'
| 'sellAsset'
| 'buyAsset'
| 'receiveAddress'
Expand Down
10 changes: 6 additions & 4 deletions src/lib/swapper/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { ChainSpecific, KnownChainIds, UtxoAccountType } from '@shapeshifto
import type { TxStatus } from '@shapeshiftoss/unchained-client'
import type { Result } from '@sniptt/monads'
import type { Asset } from 'lib/asset-service'
import type { PartialRecord } from 'lib/utils'
import type { ReduxState } from 'state/reducer'
import type { AccountMetadata } from 'state/slices/portfolioSlice/portfolioSliceCommon'

Expand Down Expand Up @@ -64,7 +65,7 @@ export type ProtocolFee = { requiresBalance: boolean } & AmountDisplayMeta

export type QuoteFeeData<T extends ChainId> = {
networkFeeCryptoBaseUnit: string | undefined // fee paid to the network from the fee asset (undefined if unknown)
protocolFees: Record<AssetId, ProtocolFee> // fee(s) paid to the protocol(s)
protocolFees: PartialRecord<AssetId, ProtocolFee> // fee(s) paid to the protocol(s)
} & ChainSpecificQuoteFeeData<T>

export type BuyAssetBySellIdInput = {
Expand All @@ -75,7 +76,7 @@ export type BuyAssetBySellIdInput = {
type CommonTradeInput = {
sellAsset: Asset
buyAsset: Asset
sellAmountBeforeFeesCryptoBaseUnit: string
sellAmountIncludingProtocolFeesCryptoBaseUnit: string
sendAddress?: string
receiveAddress: string
accountNumber: number
Expand Down Expand Up @@ -108,12 +109,12 @@ export type GetTradeQuoteInput =

export type AmountDisplayMeta = {
amountCryptoBaseUnit: string
asset: Pick<Asset, 'symbol' | 'chainId' | 'precision'>
asset: Partial<Asset> & Pick<Asset, 'symbol' | 'chainId' | 'precision'>
}

export type TradeBase<C extends ChainId> = {
buyAmountBeforeFeesCryptoBaseUnit: string
sellAmountBeforeFeesCryptoBaseUnit: string
sellAmountIncludingProtocolFeesCryptoBaseUnit: string
feeData: QuoteFeeData<C>
rate: string
sources: SwapSource[]
Expand All @@ -134,6 +135,7 @@ export type TradeQuote<C extends ChainId = ChainId> = {
recommendedSlippage?: string
id?: string
steps: TradeQuoteStep<C>[]
rate: string // top-level rate for all steps (i.e. output amount / input amount)
}

export type SwapSource = {
Expand Down
4 changes: 2 additions & 2 deletions src/lib/swapper/swappers/CowSwapper/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const cowApi: Swapper2Api = {
},

getUnsignedTx: async ({ from, tradeQuote, stepIndex }: GetUnsignedTxArgs): Promise<CowSignTx> => {
const { accountNumber, buyAsset, sellAsset, sellAmountBeforeFeesCryptoBaseUnit } =
const { accountNumber, buyAsset, sellAsset, sellAmountIncludingProtocolFeesCryptoBaseUnit } =
tradeQuote.steps[stepIndex]
const { receiveAddress } = tradeQuote

Expand All @@ -88,7 +88,7 @@ export const cowApi: Swapper2Api = {
partiallyFillable: false,
from,
kind: ORDER_KIND_SELL,
sellAmountBeforeFee: sellAmountBeforeFeesCryptoBaseUnit,
sellAmountBeforeFee: sellAmountIncludingProtocolFeesCryptoBaseUnit,
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ const expectedApiInputUsdcGnosisToXdai: CowSwapSellQuoteApiInput = {
}

const expectedTradeQuoteWethToFox: TradeQuote<KnownChainIds.EthereumMainnet> = {
id: '123',
minimumCryptoHuman: '0.01621193001101461472',
rate: '14924.80846543344314936607', // 14942 FOX per WETH
steps: [
{
allowanceContract: '0xc92e8bdf79f0507f65a392b0ab4667716bfe0110',
Expand All @@ -107,7 +109,7 @@ const expectedTradeQuoteWethToFox: TradeQuote<KnownChainIds.EthereumMainnet> = {
},
networkFeeCryptoBaseUnit: '0',
},
sellAmountBeforeFeesCryptoBaseUnit: '1000000000000000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '1000000000000000000',
buyAmountBeforeFeesCryptoBaseUnit: '14913256100953839475750', // 14913 FOX
sources: [{ name: SwapperName.CowSwap, proportion: '1' }],
buyAsset: FOX_MAINNET,
Expand All @@ -118,7 +120,9 @@ const expectedTradeQuoteWethToFox: TradeQuote<KnownChainIds.EthereumMainnet> = {
}

const expectedTradeQuoteFoxToEth: TradeQuote<KnownChainIds.EthereumMainnet> = {
id: '123',
minimumCryptoHuman: '229.09507445589919816724',
rate: '0.00004995640398295996',
steps: [
{
allowanceContract: '0xc92e8bdf79f0507f65a392b0ab4667716bfe0110',
Expand All @@ -133,7 +137,7 @@ const expectedTradeQuoteFoxToEth: TradeQuote<KnownChainIds.EthereumMainnet> = {
},
networkFeeCryptoBaseUnit: '0',
},
sellAmountBeforeFeesCryptoBaseUnit: '1000000000000000000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '1000000000000000000000',
buyAmountBeforeFeesCryptoBaseUnit: '51242479117266593',
sources: [{ name: SwapperName.CowSwap, proportion: '1' }],
buyAsset: ETH,
Expand All @@ -144,7 +148,9 @@ const expectedTradeQuoteFoxToEth: TradeQuote<KnownChainIds.EthereumMainnet> = {
}

const expectedTradeQuoteUsdcToXdai: TradeQuote<KnownChainIds.GnosisMainnet> = {
id: '123',
minimumCryptoHuman: '0.00999000999000999001',
rate: '1.0003121775396440882',
steps: [
{
allowanceContract: '0xc92e8bdf79f0507f65a392b0ab4667716bfe0110',
Expand All @@ -159,7 +165,7 @@ const expectedTradeQuoteUsdcToXdai: TradeQuote<KnownChainIds.GnosisMainnet> = {
},
networkFeeCryptoBaseUnit: '0',
},
sellAmountBeforeFeesCryptoBaseUnit: '20000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '20000000',
buyAmountBeforeFeesCryptoBaseUnit: '21006555357465608755',
sources: [{ name: SwapperName.CowSwap, proportion: '1' }],
buyAsset: XDAI,
Expand All @@ -170,7 +176,9 @@ const expectedTradeQuoteUsdcToXdai: TradeQuote<KnownChainIds.GnosisMainnet> = {
}

const expectedTradeQuoteSmallAmountWethToFox: TradeQuote<KnownChainIds.EthereumMainnet> = {
id: '123',
minimumCryptoHuman: '0.01621193001101461472',
rate: '14716.04718939437523468382', // 14716 FOX per WETH
steps: [
{
allowanceContract: '0xc92e8bdf79f0507f65a392b0ab4667716bfe0110',
Expand All @@ -185,7 +193,7 @@ const expectedTradeQuoteSmallAmountWethToFox: TradeQuote<KnownChainIds.EthereumM
},
networkFeeCryptoBaseUnit: '0',
},
sellAmountBeforeFeesCryptoBaseUnit: '1000000000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '1000000000000',
buyAmountBeforeFeesCryptoBaseUnit: '0', // 0 FOX
sources: [{ name: SwapperName.CowSwap, proportion: '1' }],
buyAsset: FOX_MAINNET,
Expand All @@ -201,7 +209,7 @@ describe('getCowTradeQuote', () => {
chainId: KnownChainIds.EthereumMainnet,
sellAsset: ETH,
buyAsset: FOX_MAINNET,
sellAmountBeforeFeesCryptoBaseUnit: '11111',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '11111',
accountNumber: 0,
receiveAddress: DEFAULT_ADDRESS,
affiliateBps: '0',
Expand Down Expand Up @@ -229,7 +237,7 @@ describe('getCowTradeQuote', () => {
chainId: KnownChainIds.EthereumMainnet,
sellAsset: WETH,
buyAsset: FOX_MAINNET,
sellAmountBeforeFeesCryptoBaseUnit: '1000000000000000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '1000000000000000000',
accountNumber: 0,
receiveAddress: DEFAULT_ADDRESS,
affiliateBps: '0',
Expand All @@ -242,6 +250,7 @@ describe('getCowTradeQuote', () => {
Promise.resolve(
Ok({
data: {
id: 123,
quote: {
...expectedApiInputWethToFox,
sellAmountBeforeFee: undefined,
Expand Down Expand Up @@ -274,7 +283,7 @@ describe('getCowTradeQuote', () => {
chainId: KnownChainIds.EthereumMainnet,
sellAsset: FOX_MAINNET,
buyAsset: ETH,
sellAmountBeforeFeesCryptoBaseUnit: '1000000000000000000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '1000000000000000000000',
accountNumber: 0,
receiveAddress: DEFAULT_ADDRESS,
affiliateBps: '0',
Expand All @@ -287,6 +296,7 @@ describe('getCowTradeQuote', () => {
Promise.resolve(
Ok({
data: {
id: 123,
quote: {
...expectedApiInputFoxToEth,
sellAmountBeforeFee: undefined,
Expand Down Expand Up @@ -319,7 +329,7 @@ describe('getCowTradeQuote', () => {
chainId: KnownChainIds.GnosisMainnet,
sellAsset: USDC_GNOSIS,
buyAsset: XDAI,
sellAmountBeforeFeesCryptoBaseUnit: '20000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '20000000',
accountNumber: 0,
receiveAddress: DEFAULT_ADDRESS,
affiliateBps: '0',
Expand All @@ -332,6 +342,7 @@ describe('getCowTradeQuote', () => {
Promise.resolve(
Ok({
data: {
id: 123,
quote: {
...expectedApiInputUsdcGnosisToXdai,
sellAmountBeforeFee: undefined,
Expand Down Expand Up @@ -364,7 +375,7 @@ describe('getCowTradeQuote', () => {
chainId: KnownChainIds.EthereumMainnet,
sellAsset: WETH,
buyAsset: FOX_MAINNET,
sellAmountBeforeFeesCryptoBaseUnit: '1000000000000',
sellAmountIncludingProtocolFeesCryptoBaseUnit: '1000000000000',
accountNumber: 0,
receiveAddress: DEFAULT_ADDRESS,
affiliateBps: '0',
Expand All @@ -377,6 +388,7 @@ describe('getCowTradeQuote', () => {
Promise.resolve(
Ok({
data: {
id: 123,
quote: {
...expectedApiInputSmallAmountWethToFox,
sellAmountBeforeFee: undefined,
Expand Down
Loading