Skip to content

Commit

Permalink
feat: 1inch swapper pre-release second pass fixes (shapeshift#4433)
Browse files Browse the repository at this point in the history
  • Loading branch information
woodenfurniture authored May 5, 2023
1 parent debc3c0 commit 1a74f1f
Show file tree
Hide file tree
Showing 19 changed files with 115 additions and 274 deletions.
3 changes: 3 additions & 0 deletions .env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,6 @@ REACT_APP_THORCHAIN_NODE_URL=https://dev-daemon.thorchain.shapeshift.com

# thorchain
REACT_APP_MIDGARD_URL=https://dev-indexer.thorchain.shapeshift.com/v2

# 1inch Swap
REACT_APP_FEATURE_ONE_INCH=true
4 changes: 4 additions & 0 deletions .env.develop
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,7 @@ REACT_APP_MIDGARD_URL=https://dev-indexer.thorchain.shapeshift.com/v2

# Osmosis
REACT_APP_FEATURE_OSMOSIS_SEND=true


# 1inch Swap
REACT_APP_FEATURE_ONE_INCH=true
3 changes: 3 additions & 0 deletions .env.e2e
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ REACT_APP_THORCHAIN_NODE_URL=https://dev-daemon.thorchain.shapeshift.com

# thorchain
REACT_APP_MIDGARD_URL=https://dev-indexer.thorchain.shapeshift.com/v2

# 1inch Swap
REACT_APP_FEATURE_ONE_INCH=true
3 changes: 3 additions & 0 deletions .env.private
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ REACT_APP_THORCHAIN_NODE_URL=https://daemon.thorchain.shapeshift.com

# thorchain
REACT_APP_MIDGARD_URL=https://indexer.thorchain.shapeshift.com/v2

# 1inch Swap
REACT_APP_FEATURE_ONE_INCH=false
3 changes: 2 additions & 1 deletion src/assets/translations/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,8 @@
"intermediaryTransactionOutputs": {
"prefix": "or",
"suffix": "on %{chainName}"
}
},
"unknownGas": "(unknown)"
},
"modals": {
"popup": {
Expand Down
19 changes: 13 additions & 6 deletions src/components/Trade/Components/TradeQuotes/TradeQuote.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useIsTradingActive } from 'components/Trade/hooks/useIsTradingActive'
import { bnOrZero } from 'lib/bignumber/bignumber'
import { fromBaseUnit } from 'lib/math'
import type { SwapperWithQuoteMetadata } from 'lib/swapper/api'
import { SwapperType } from 'lib/swapper/api'
import { SwapperName, SwapperType } from 'lib/swapper/api'
import { assertUnreachable } from 'lib/utils'
import { selectFeeAssetByChainId, selectFeeAssetById } from 'state/slices/selectors'
import { useAppSelector } from 'state/store'
Expand Down Expand Up @@ -122,9 +122,9 @@ export const TradeQuoteLoaded: React.FC<TradeQuoteLoadedProps> = ({
throw new Error(`TradeQuoteLoaded: no fee asset found for chainId ${sellAsset?.chainId}!`)

const networkFeeFiat = feeAssetFiatRate
? bnOrZero(fromBaseUnit(quote.feeData.networkFeeCryptoBaseUnit, feeAsset.precision))
.times(feeAssetFiatRate)
.toString()
? bnOrZero(fromBaseUnit(quote.feeData.networkFeeCryptoBaseUnit, feeAsset.precision)).times(
feeAssetFiatRate,
)
: undefined

const protocol = swapperWithMetadata.swapper.name
Expand Down Expand Up @@ -187,7 +187,7 @@ export const TradeQuoteLoaded: React.FC<TradeQuoteLoadedProps> = ({
}
}, [swapperWithMetadata])

return networkFeeFiat && totalReceiveAmountCryptoPrecision ? (
return totalReceiveAmountCryptoPrecision ? (
<Flex
borderWidth={1}
cursor='pointer'
Expand Down Expand Up @@ -218,7 +218,14 @@ export const TradeQuoteLoaded: React.FC<TradeQuoteLoadedProps> = ({
<RawText color='gray.500'>
<FaGasPump />
</RawText>
<Amount.Fiat value={networkFeeFiat} />
{
// We cannot infer gas fees for 1inch swapper before an amount is entered
!isAmountEntered && protocol === SwapperName.OneInch ? (
translate('trade.unknownGas')
) : (
<Amount.Fiat value={bnOrZero(networkFeeFiat).toString()} />
)
}
</Flex>
</Flex>
<Flex justifyContent='space-between' alignItems='center'>
Expand Down
21 changes: 11 additions & 10 deletions src/components/Trade/hooks/useAvailableSwappers.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import partition from 'lodash/partition'
import { useEffect, useState } from 'react'
import { getSwapperManager } from 'components/Trade/hooks/useSwapper/swapperManager'
import { useTradeQuoteService } from 'components/Trade/hooks/useTradeQuoteService'
import type { GetSwappersWithQuoteMetadataReturn, SwapperWithQuoteMetadata } from 'lib/swapper/api'
import type { GetSwappersWithQuoteMetadataReturn } from 'lib/swapper/api'
import { SwapperName } from 'lib/swapper/api'
import { isSome } from 'lib/utils'
import { getIsTradingActiveApi } from 'state/apis/swapper/getIsTradingActiveApi'
Expand Down Expand Up @@ -122,9 +123,7 @@ export const useAvailableSwappers = () => {
The available swappers endpoint returns all available swappers for a given trade pair, ordered by rate, including halted.
A halted swapper may well have the best rate, but we don't want to show it unless there are none other available.
*/
const active: SwapperWithQuoteMetadata[] = []
const halted: SwapperWithQuoteMetadata[] = []
await Promise.all(
const swappersWithQuoteMetadataAndTradingStatus = await Promise.all(
swappersWithQuoteMetadata.map(async swapperWithQuoteMetadata => {
const isActive = await (async () => {
const activeSwapper = swapperWithQuoteMetadata.swapper
Expand Down Expand Up @@ -158,19 +157,21 @@ export const useAvailableSwappers = () => {
} else return true
})()

if (isActive) {
active.push(swapperWithQuoteMetadata)
} else {
halted.push(swapperWithQuoteMetadata)
}
return { swapperWithQuoteMetadata, isActive }
}),
)

/*
If we have active swappers, show only them. Else, show any halted swappers so the user knows the trade pair
is actually supported by us, it's just currently halted.
*/
const swappersToDisplay = active.length > 0 ? active : halted
const [active, halted] = partition(
swappersWithQuoteMetadataAndTradingStatus,
({ isActive }) => isActive,
)
const swappersToDisplay = (active.length > 0 ? active : halted).map(
({ swapperWithQuoteMetadata }) => swapperWithQuoteMetadata,
)
const activeSwapperWithQuoteMetadata = swappersToDisplay?.[0]
updateAvailableSwappersWithMetadata(swappersToDisplay)
updateActiveSwapperWithMetadata(activeSwapperWithQuoteMetadata)
Expand Down
27 changes: 16 additions & 11 deletions src/lib/swapper/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ type ChainSpecificQuoteFeeData<T extends ChainId> = ChainSpecific<
}
>

export type QuoteFeeData<T extends ChainId> = {
networkFeeCryptoBaseUnit: string // fee paid to the network from the fee asset
export type QuoteFeeData<T extends ChainId, MissingNetworkFee extends boolean = false> = {
networkFeeCryptoBaseUnit: MissingNetworkFee extends true ? undefined : string // fee paid to the network from the fee asset
buyAssetTradeFeeUsd: string // fee taken out of the trade from the buyAsset
sellAssetTradeFeeUsd?: string // fee taken out of the trade from the sellAsset
} & ChainSpecificQuoteFeeData<T>
Expand Down Expand Up @@ -140,10 +140,10 @@ export type IntermediaryTransactionOutput = {
buyAmountCryptoBaseUnit: string
}

interface TradeBase<C extends ChainId> {
interface TradeBase<C extends ChainId, MissingNetworkFee extends boolean = false> {
buyAmountCryptoBaseUnit: string
sellAmountBeforeFeesCryptoBaseUnit: string
feeData: QuoteFeeData<C>
feeData: QuoteFeeData<C, MissingNetworkFee>
rate: string
sources: SwapSource[]
buyAsset: Asset
Expand All @@ -152,17 +152,15 @@ interface TradeBase<C extends ChainId> {
intermediaryTransactionOutputs?: IntermediaryTransactionOutput[]
}

export interface TradeQuote<C extends ChainId> extends TradeBase<C> {
export interface TradeQuote<C extends ChainId, UnknownNetworkFee extends boolean = false>
extends TradeBase<C, UnknownNetworkFee> {
allowanceContract: string
minimumCryptoHuman: string
maximumCryptoHuman: string
recommendedSlippage?: string

/** @deprecated Use minimumCryptoHuman instead */
minimum?: string
}

export interface Trade<C extends ChainId> extends TradeBase<C> {
export interface Trade<C extends ChainId> extends TradeBase<C, false> {
receiveAddress: string
receiveAccountNumber?: number
}
Expand Down Expand Up @@ -271,7 +269,7 @@ export enum SwapErrorType {
// Catch-all for happy responses, but entity not found according to our criteria
NOT_FOUND = 'NOT_FOUND',
}
export interface Swapper<T extends ChainId> {
export interface Swapper<T extends ChainId, MaybeUnknownNetworkFee extends boolean = false> {
/** Human-readable swapper name */
readonly name: SwapperName

Expand All @@ -288,7 +286,14 @@ export interface Swapper<T extends ChainId> {
/**
* Get a trade quote
*/
getTradeQuote(input: GetTradeQuoteInput): Promise<Result<TradeQuote<ChainId>, SwapErrorRight>>
getTradeQuote(
input: GetTradeQuoteInput,
): Promise<
Result<
TradeQuote<ChainId, MaybeUnknownNetworkFee extends true ? true | false : false>,
SwapErrorRight
>
>
/**
* Get the usd rate from either the assets symbol or tokenId
*/
Expand Down
16 changes: 8 additions & 8 deletions src/lib/swapper/manager/SwapperManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ export class SwapperManager {
public swappers: Map<SwapperType, Swapper<ChainId>>

constructor() {
this.swappers = new Map<SwapperType, Swapper<ChainId>>()
this.swappers = new Map<SwapperType, Swapper<ChainId, boolean>>()
}

/**
*
* @param swapperInstance swapper instance {Swapper}
* @returns {SwapperManager}
*/
addSwapper(swapperInstance: Swapper<ChainId>): this {
addSwapper(swapperInstance: Swapper<ChainId, boolean>): this {
validateSwapper(swapperInstance)
const swapperType = swapperInstance.getType()
this.swappers.set(swapperType, swapperInstance)
Expand All @@ -49,7 +49,7 @@ export class SwapperManager {
* @param swapperType swapper type {SwapperType|string}
* @returns {Swapper}
*/
getSwapper(swapperType: SwapperType): Swapper<ChainId> {
getSwapper(swapperType: SwapperType): Swapper<ChainId, boolean> {
const swapper = this.swappers.get(swapperType)
if (!swapper)
throw new SwapError('[getSwapper] - swapperType doesnt exist', {
Expand Down Expand Up @@ -88,7 +88,7 @@ export class SwapperManager {
const { sellAsset, buyAsset, feeAsset } = args

// Get all swappers that support the pair
const supportedSwappers: Swapper<ChainId>[] = this.getSwappersByPair({
const supportedSwappers: Swapper<ChainId, boolean>[] = this.getSwappersByPair({
sellAssetId: sellAsset.assetId,
buyAssetId: buyAsset.assetId,
})
Expand Down Expand Up @@ -127,18 +127,18 @@ export class SwapperManager {
* @param pair type {GetQuoteInput}
* @returns {SwapperType}
*/
getSwappersByPair(pair: ByPairInput): Swapper<ChainId>[] {
getSwappersByPair(pair: ByPairInput): Swapper<ChainId, boolean>[] {
const { sellAssetId, buyAssetId } = pair
const availableSwappers = Array.from(this.swappers.values())
return availableSwappers.filter(
(swapper: Swapper<ChainId>) =>
(swapper: Swapper<ChainId, boolean>) =>
swapper.filterBuyAssetsBySellAssetId({ sellAssetId, assetIds: [buyAssetId] }).length,
)
}

getSupportedBuyAssetIdsFromSellId(args: BuyAssetBySellIdInput) {
return uniq(
Array.from(this.swappers.values()).flatMap((swapper: Swapper<ChainId>) =>
Array.from(this.swappers.values()).flatMap((swapper: Swapper<ChainId, boolean>) =>
swapper.filterBuyAssetsBySellAssetId(args),
),
)
Expand All @@ -148,7 +148,7 @@ export class SwapperManager {
const { assetIds } = args

return uniq(
Array.from(this.swappers.values()).flatMap((swapper: Swapper<ChainId>) =>
Array.from(this.swappers.values()).flatMap((swapper: Swapper<ChainId, boolean>) =>
swapper.filterAssetIdsBySellable(assetIds),
),
)
Expand Down
2 changes: 1 addition & 1 deletion src/lib/swapper/manager/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ export const getRatioFromQuote = async (
const totalSendAmountFiat = totalSellAmountFiat.plus(networkFeeFiat)
const ratio = totalReceiveAmountFiat.div(totalSendAmountFiat)

return ratio.isFinite() ? ratio.toNumber() : undefined
return ratio.isFinite() && !networkFeeFiat.isZero() ? ratio.toNumber() : -Infinity
}
6 changes: 3 additions & 3 deletions src/lib/swapper/swappers/LifiSwapper/LifiSwapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import type {
TradeTxs,
} from 'lib/swapper/api'
import { SwapperName, SwapperType } from 'lib/swapper/api'
import { approvalNeeded } from 'lib/swapper/swappers/LifiSwapper/approvalNeeded/approvalNeeded'
import { buildTrade } from 'lib/swapper/swappers/LifiSwapper/buildTrade/buildTrade'
import { executeTrade } from 'lib/swapper/swappers/LifiSwapper/executeTrade/executeTrade'
import { getTradeQuote } from 'lib/swapper/swappers/LifiSwapper/getTradeQuote/getTradeQuote'
Expand All @@ -36,12 +35,13 @@ import type {
LifiTrade,
LifiTradeQuote,
} from 'lib/swapper/swappers/LifiSwapper/utils/types'
import { approvalNeeded } from 'lib/swapper/swappers/utils/approvalNeeded/approvalNeeded'
import { approveAmount, approveInfinite } from 'lib/swapper/swappers/utils/approve/approve'
import { filterEvmAssetIdsBySellable } from 'lib/swapper/swappers/utils/filterAssetIdsBySellable/filterAssetIdsBySellable'
import { filterCrossChainEvmBuyAssetsBySellAssetId } from 'lib/swapper/swappers/utils/filterBuyAssetsBySellAssetId/filterBuyAssetsBySellAssetId'
import { createEmptyEvmTradeQuote } from 'lib/swapper/swappers/utils/helpers/helpers'

export class LifiSwapper implements Swapper<EvmChainId> {
export class LifiSwapper implements Swapper<EvmChainId, true> {
readonly name = SwapperName.LIFI
private lifiChainMap: Map<ChainId, LifiChainKey> = new Map()
private executedTrades: Map<string, GetStatusRequest> = new Map()
Expand Down Expand Up @@ -79,7 +79,7 @@ export class LifiSwapper implements Swapper<EvmChainId> {
*/
async getTradeQuote(
input: GetEvmTradeQuoteInput,
): Promise<Result<LifiTradeQuote, SwapErrorRight>> {
): Promise<Result<LifiTradeQuote<true | false>, SwapErrorRight>> {
const minimumCryptoHuman = getMinimumCryptoHuman(input.sellAsset)
const minimumSellAmountBaseUnit = toBaseUnit(minimumCryptoHuman, input.sellAsset.precision)
const isBelowMinSellAmount = bnOrZero(input.sellAmountBeforeFeesCryptoBaseUnit).lt(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import type { LifiTradeQuote } from 'lib/swapper/swappers/LifiSwapper/utils/type
export async function getTradeQuote(
input: GetEvmTradeQuoteInput,
lifiChainMap: Map<ChainId, ChainKey>,
): Promise<Result<LifiTradeQuote, SwapErrorRight>> {
): Promise<Result<LifiTradeQuote<false>, SwapErrorRight>> {
try {
const {
chainId,
Expand Down
3 changes: 2 additions & 1 deletion src/lib/swapper/swappers/LifiSwapper/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface LifiExecuteTradeInput extends Omit<ExecuteTradeInput<EvmChainId
trade: LifiTrade
}

export interface LifiTradeQuote extends TradeQuote<EvmChainId> {
export interface LifiTradeQuote<MaybeUnknownNetworkFee extends boolean>
extends TradeQuote<EvmChainId, MaybeUnknownNetworkFee> {
selectedLifiRoute?: Route
}
Loading

0 comments on commit 1a74f1f

Please sign in to comment.