Skip to content

Commit

Permalink
feat: split trade rates and quotes final wire-up (#8079)
Browse files Browse the repository at this point in the history
  • Loading branch information
gomesalexandre authored Nov 20, 2024
1 parent abd0d45 commit bd8ac25
Show file tree
Hide file tree
Showing 69 changed files with 2,722 additions and 2,304 deletions.
2 changes: 1 addition & 1 deletion .env.base
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ REACT_APP_FEATURE_FOX_PAGE_FOX_FARMING_SECTION=true
REACT_APP_FEATURE_FOX_PAGE_GOVERNANCE=true
REACT_APP_FEATURE_PHANTOM_WALLET=true
REACT_APP_FEATURE_ZRX_PERMIT2=true
REACT_APP_FEATURE_PUBLIC_TRADE_ROUTE=false
REACT_APP_FEATURE_PUBLIC_TRADE_ROUTE=true
REACT_APP_FEATURE_THOR_FREE_FEES=true
REACT_APP_FEATURE_LIMIT_ORDERS=false

Expand Down
4 changes: 2 additions & 2 deletions packages/contracts/src/contractManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ export const getOrCreateContractByType: <A extends KnownContractAddress, T exten
type,
chainId,
}: {
address: string | `0x${string}`
address: string | Address
type: T
chainId: ChainId
}) => KnownContractByType<A, T> = <A extends KnownContractAddress, T extends ContractType>({
address,
type,
chainId,
}: {
address: string | `0x${string}`
address: string | Address
type: T
chainId: ChainId
}): KnownContractByType<A, T> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import type {
TradeRate,
} from '../../types'
import { checkEvmSwapStatus, getHopByIndex, isExecutableTradeQuote } from '../../utils'
import { getTradeQuote, getTradeRate } from './getTradeQuote/getTradeQuote'
import { getTradeQuote } from './getTradeQuote/getTradeQuote'
import { getTradeRate } from './getTradeRate/getTradeRate'
import { fetchArbitrumBridgeQuote } from './utils/fetchArbitrumBridgeSwap'
import { assertValidTrade } from './utils/helpers'

Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,24 @@
import { ethChainId } from '@shapeshiftoss/caip'
import { type HDWallet, supportsETH } from '@shapeshiftoss/hdwallet-core'
import { supportsETH } from '@shapeshiftoss/hdwallet-core'
import type { Result } from '@sniptt/monads'
import { Err, Ok } from '@sniptt/monads'
import { v4 as uuid } from 'uuid'

import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constants'
import type {
GetEvmTradeQuoteInput,
GetEvmTradeQuoteInputBase,
GetEvmTradeRateInput,
SingleHopTradeQuoteSteps,
SingleHopTradeRateSteps,
SwapErrorRight,
SwapperDeps,
TradeQuote,
TradeRate,
} from '../../../types'
import { SwapperName, TradeQuoteError } from '../../../types'
import { makeSwapErrorRight } from '../../../utils'
import type { ArbitrumBridgeTradeQuote, GetEvmTradeQuoteInputWithWallet } from '../types'
import type { FetchArbitrumBridgeQuoteInput } from '../utils/fetchArbitrumBridgeSwap'
import {
fetchArbitrumBridgePrice,
fetchArbitrumBridgeQuote,
} from '../utils/fetchArbitrumBridgeSwap'
import { fetchArbitrumBridgeQuote } from '../utils/fetchArbitrumBridgeSwap'
import { assertValidTrade } from '../utils/helpers'

export type GetEvmTradeQuoteInputWithWallet = Omit<GetEvmTradeQuoteInputBase, 'supportsEIP1559'> & {
wallet: HDWallet
}

type ArbitrumBridgeSpecificMetadata = {
direction: 'deposit' | 'withdrawal'
}

export type ArbitrumBridgeTradeQuote = TradeQuote & ArbitrumBridgeSpecificMetadata
export type ArbitrumBridgeTradeRate = TradeRate & ArbitrumBridgeSpecificMetadata

export const isArbitrumBridgeTradeQuote = (
quote: TradeQuote | undefined,
): quote is ArbitrumBridgeTradeQuote => !!quote && 'direction' in quote
Expand Down Expand Up @@ -138,86 +121,3 @@ export async function getTradeQuote(
)
}
}

export async function getTradeRate(
input: GetEvmTradeRateInput,
{ assertGetEvmChainAdapter }: SwapperDeps,
): Promise<Result<ArbitrumBridgeTradeRate, SwapErrorRight>> {
const {
chainId,
sellAsset,
buyAsset,
supportsEIP1559,
receiveAddress,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
sendAddress,
} = input

const assertion = await assertValidTrade({ buyAsset, sellAsset })
if (assertion.isErr()) return Err(assertion.unwrapErr())

const isDeposit = sellAsset.chainId === ethChainId

// 15 minutes for deposits, 7 days for withdrawals
const estimatedExecutionTimeMs = isDeposit ? 15 * 60 * 1000 : 7 * 24 * 60 * 60 * 1000

// 1/1 when bridging on Arbitrum bridge
const rate = '1'

try {
const args = {
supportsEIP1559,
chainId,
buyAsset,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
sellAsset,
sendAddress,
receiveAddress,
assertGetEvmChainAdapter,
quoteOrRate: 'rate',
}
const swap = await fetchArbitrumBridgePrice(args)

const buyAmountBeforeFeesCryptoBaseUnit = sellAmountIncludingProtocolFeesCryptoBaseUnit
const buyAmountAfterFeesCryptoBaseUnit = sellAmountIncludingProtocolFeesCryptoBaseUnit

return Ok({
id: uuid(),
accountNumber: undefined,
receiveAddress,
affiliateBps: '0',
potentialAffiliateBps: '0',
rate,
slippageTolerancePercentageDecimal: getDefaultSlippageDecimalPercentageForSwapper(
SwapperName.ArbitrumBridge,
),
steps: [
{
estimatedExecutionTimeMs,
allowanceContract: swap.allowanceContract,
rate,
buyAsset,
sellAsset,
accountNumber: undefined,
buyAmountBeforeFeesCryptoBaseUnit,
buyAmountAfterFeesCryptoBaseUnit,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
feeData: {
protocolFees: {},
networkFeeCryptoBaseUnit: swap.networkFeeCryptoBaseUnit,
},
source: SwapperName.ArbitrumBridge,
},
] as SingleHopTradeRateSteps,
direction: isDeposit ? ('deposit' as const) : ('withdrawal' as const),
})
} catch (err) {
return Err(
makeSwapErrorRight({
message: '[ArbitrumBridge: tradeQuote] - failed to get fee data',
cause: err,
code: TradeQuoteError.NetworkFeeEstimationFailed,
}),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { ethChainId } from '@shapeshiftoss/caip'
import { type HDWallet } from '@shapeshiftoss/hdwallet-core'
import type { Result } from '@sniptt/monads'
import { Err, Ok } from '@sniptt/monads'
import { v4 as uuid } from 'uuid'

import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constants'
import type {
GetEvmTradeQuoteInputBase,
GetEvmTradeRateInput,
SingleHopTradeRateSteps,
SwapErrorRight,
SwapperDeps,
} from '../../../types'
import { SwapperName, TradeQuoteError } from '../../../types'
import { makeSwapErrorRight } from '../../../utils'
import type { ArbitrumBridgeTradeRate } from '../types'
import { fetchArbitrumBridgePrice } from '../utils/fetchArbitrumBridgeSwap'
import { assertValidTrade } from '../utils/helpers'

export type GetEvmTradeQuoteInputWithWallet = Omit<GetEvmTradeQuoteInputBase, 'supportsEIP1559'> & {
wallet: HDWallet
}

export async function getTradeRate(
input: GetEvmTradeRateInput,
{ assertGetEvmChainAdapter }: SwapperDeps,
): Promise<Result<ArbitrumBridgeTradeRate, SwapErrorRight>> {
const {
chainId,
sellAsset,
buyAsset,
supportsEIP1559,
receiveAddress,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
sendAddress,
} = input

const assertion = await assertValidTrade({ buyAsset, sellAsset })
if (assertion.isErr()) return Err(assertion.unwrapErr())

const isDeposit = sellAsset.chainId === ethChainId

// 15 minutes for deposits, 7 days for withdrawals
const estimatedExecutionTimeMs = isDeposit ? 15 * 60 * 1000 : 7 * 24 * 60 * 60 * 1000

// 1/1 when bridging on Arbitrum bridge
const rate = '1'

try {
const args = {
supportsEIP1559,
chainId,
buyAsset,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
sellAsset,
sendAddress,
receiveAddress,
assertGetEvmChainAdapter,
quoteOrRate: 'rate',
}
const swap = await fetchArbitrumBridgePrice(args)

const buyAmountBeforeFeesCryptoBaseUnit = sellAmountIncludingProtocolFeesCryptoBaseUnit
const buyAmountAfterFeesCryptoBaseUnit = sellAmountIncludingProtocolFeesCryptoBaseUnit

return Ok({
id: uuid(),
accountNumber: undefined,
receiveAddress: undefined,
affiliateBps: '0',
potentialAffiliateBps: '0',
rate,
slippageTolerancePercentageDecimal: getDefaultSlippageDecimalPercentageForSwapper(
SwapperName.ArbitrumBridge,
),
steps: [
{
estimatedExecutionTimeMs,
allowanceContract: swap.allowanceContract,
rate,
buyAsset,
sellAsset,
accountNumber: undefined,
buyAmountBeforeFeesCryptoBaseUnit,
buyAmountAfterFeesCryptoBaseUnit,
sellAmountIncludingProtocolFeesCryptoBaseUnit,
feeData: {
protocolFees: {},
networkFeeCryptoBaseUnit: swap.networkFeeCryptoBaseUnit,
},
source: SwapperName.ArbitrumBridge,
},
] as SingleHopTradeRateSteps,
direction: isDeposit ? ('deposit' as const) : ('withdrawal' as const),
})
} catch (err) {
return Err(
makeSwapErrorRight({
message: '[ArbitrumBridge: tradeQuote] - failed to get fee data',
cause: err,
code: TradeQuoteError.NetworkFeeEstimationFailed,
}),
)
}
}
15 changes: 15 additions & 0 deletions packages/swapper/src/swappers/ArbitrumBridgeSwapper/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import type { HDWallet } from '@shapeshiftoss/hdwallet-core'

import type { GetEvmTradeQuoteInputBase, TradeQuote, TradeRate } from '../../types'

export enum BRIDGE_TYPE {
ETH_DEPOSIT = 'ETH Deposit',
ERC20_DEPOSIT = 'ERC20 Deposit',
ETH_WITHDRAWAL = 'ETH Withdrawal',
ERC20_WITHDRAWAL = 'ERC20 Withdrawal',
}

export type GetEvmTradeQuoteInputWithWallet = Omit<GetEvmTradeQuoteInputBase, 'supportsEIP1559'> & {
wallet: HDWallet
}

type ArbitrumBridgeSpecificMetadata = {
direction: 'deposit' | 'withdrawal'
}

export type ArbitrumBridgeTradeQuote = TradeQuote & ArbitrumBridgeSpecificMetadata
export type ArbitrumBridgeTradeRate = TradeRate & ArbitrumBridgeSpecificMetadata
3 changes: 2 additions & 1 deletion packages/swapper/src/swappers/ChainflipSwapper/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import type {
import { isExecutableTradeQuote, isExecutableTradeStep, isToken } from '../../utils'
import { CHAINFLIP_BAAS_COMMISSION } from './constants'
import type { ChainflipBaasSwapDepositAddress } from './models/ChainflipBaasSwapDepositAddress'
import { getTradeQuote, getTradeRate } from './swapperApi/getTradeQuote'
import { getTradeQuote } from './swapperApi/getTradeQuote'
import { getTradeRate } from './swapperApi/getTradeRate'
import type { ChainFlipStatus } from './types'
import { chainflipService } from './utils/chainflipService'
import { getLatestChainflipStatusMessage } from './utils/getLatestChainflipStatusMessage'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ import { v4 as uuid } from 'uuid'
import { getDefaultSlippageDecimalPercentageForSwapper } from '../../../constants'
import type {
CommonTradeQuoteInput,
GetTradeRateInput,
GetUtxoTradeQuoteInput,
SwapErrorRight,
SwapperDeps,
TradeQuote,
TradeRate,
} from '../../../types'
import {
type GetEvmTradeQuoteInput,
Expand All @@ -40,7 +38,7 @@ import { getEvmTxFees } from '../utils/getEvmTxFees'
import { getUtxoTxFees } from '../utils/getUtxoTxFees'
import { getChainFlipIdFromAssetId, isSupportedAssetId, isSupportedChainId } from '../utils/helpers'

const _getTradeQuote = async (
export const _getTradeQuote = async (
input: CommonTradeQuoteInput,
deps: SwapperDeps,
): Promise<Result<TradeQuote[], SwapErrorRight>> => {
Expand Down Expand Up @@ -343,16 +341,6 @@ const _getTradeQuote = async (
return Ok(quotes)
}

// This isn't a mistake. A trade rate *is* a trade quote. Chainflip doesn't really have a notion of a trade quote,
// they do have a notion of a "swap" (which we effectively only use to get the deposit address), which is irrelevant to the notion of quote vs. rate
export const getTradeRate = async (
input: GetTradeRateInput,
deps: SwapperDeps,
): Promise<Result<TradeRate[], SwapErrorRight>> => {
const rates = await _getTradeQuote(input as unknown as CommonTradeQuoteInput, deps)
return rates as Result<TradeRate[], SwapErrorRight>
}

export const getTradeQuote = async (
input: CommonTradeQuoteInput,
deps: SwapperDeps,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Result } from '@sniptt/monads'

import type {
CommonTradeQuoteInput,
GetTradeRateInput,
SwapErrorRight,
SwapperDeps,
TradeRate,
} from '../../../types'
import { _getTradeQuote } from './getTradeQuote'

// This isn't a mistake. A trade rate *is* a trade quote. Chainflip doesn't really have a notion of a trade quote,
// they do have a notion of a "swap" (which we effectively only use to get the deposit address), which is irrelevant to the notion of quote vs. rate
export const getTradeRate = async (
input: GetTradeRateInput,
deps: SwapperDeps,
): Promise<Result<TradeRate[], SwapErrorRight>> => {
const rates = await _getTradeQuote(input as unknown as CommonTradeQuoteInput, deps)
return rates as Result<TradeRate[], SwapErrorRight>
}
Loading

0 comments on commit bd8ac25

Please sign in to comment.