Skip to content

Commit

Permalink
Merge branch 'develop' into cross-account-1inch
Browse files Browse the repository at this point in the history
  • Loading branch information
gomesalexandre authored Dec 12, 2023
2 parents bffb3eb + b6c9b88 commit b2cf2e7
Show file tree
Hide file tree
Showing 50 changed files with 225 additions and 317 deletions.
4 changes: 2 additions & 2 deletions packages/chain-adapters/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { AssetId, ChainId } from '@shapeshiftoss/caip'
import type { BIP44Params, UtxoAccountType } from '@shapeshiftoss/types'
import type { BIP44Params, KnownChainIds, UtxoAccountType } from '@shapeshiftoss/types'

import type {
Account,
Expand All @@ -23,7 +23,7 @@ import type {
/**
* Type alias for a Map that can be used to manage instances of ChainAdapters
*/
export type ChainAdapterManager = Map<ChainId, ChainAdapter<ChainId>>
export type ChainAdapterManager = Map<ChainId, ChainAdapter<KnownChainIds>>

export type ChainAdapter<T extends ChainId> = {
/**
Expand Down
11 changes: 7 additions & 4 deletions src/components/AuroraBackground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ const canvasStyle: CSSProperties = {
}

export const AuroraBackground: React.FC = props => {
const canvasRefB = useRef(null)
const canvasRefB = useRef<HTMLCanvasElement>(null)

useEffect(() => {
let center = [0, 0]
Expand All @@ -47,9 +47,12 @@ export const AuroraBackground: React.FC = props => {
let rayProps: Float32Array
let animationFrameId: number
const canvasA = document.createElement('canvas')
const canvasB: HTMLCanvasElement = canvasRefB.current as unknown as HTMLCanvasElement
const ctxA = canvasA.getContext('2d') as unknown as CanvasRenderingContext2D
const ctxB = canvasB.getContext('2d') as unknown as CanvasRenderingContext2D
const canvasB: HTMLCanvasElement | null = canvasRefB.current
const ctxA: CanvasRenderingContext2D | null = canvasA.getContext('2d')
const ctxB: CanvasRenderingContext2D | null =
canvasB !== null ? canvasB.getContext('2d') : canvasB

if (canvasB === null || ctxA === null || ctxB === null) return

const setup = () => {
resize()
Expand Down
12 changes: 3 additions & 9 deletions src/components/Layout/Header/NavBar/ChainMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
} from '@chakra-ui/react'
import type { ChainId } from '@shapeshiftoss/caip'
import { fromChainId, gnosisChainId } from '@shapeshiftoss/caip'
import type { EvmBaseAdapter, EvmChainId } from '@shapeshiftoss/chain-adapters'
import type { ETHWallet } from '@shapeshiftoss/hdwallet-core'
import { supportsEthSwitchChain } from '@shapeshiftoss/hdwallet-core'
import { utils } from 'ethers'
Expand All @@ -26,6 +25,7 @@ import { CircleIcon } from 'components/Icons/Circle'
import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton'
import { useEvm } from 'hooks/useEvm/useEvm'
import { useWallet } from 'hooks/useWallet/useWallet'
import { assertGetEvmChainAdapter } from 'lib/utils/evm'
import { selectAssetById, selectAssets } from 'state/slices/selectors'
import { useAppSelector } from 'state/store'

Expand Down Expand Up @@ -92,13 +92,7 @@ export const ChainMenu = memo((props: ChainMenuProps) => {
throw new Error(`Unsupported EVM network: ${requestedEthNetwork}`)
}

const requestedChainChainAdapter = chainAdapterManager.get(requestedChainId) as unknown as
| EvmBaseAdapter<EvmChainId>
| undefined

if (!requestedChainChainAdapter) {
throw new Error(`No chain adapter found for: ${requestedChainId}`)
}
const requestedChainChainAdapter = assertGetEvmChainAdapter(requestedChainId)

const requestedChainFeeAssetId = requestedChainChainAdapter.getFeeAssetId()
const requestedChainFeeAsset = assets[requestedChainFeeAssetId]
Expand Down Expand Up @@ -128,7 +122,7 @@ export const ChainMenu = memo((props: ChainMenuProps) => {
console.error(e)
}
},
[assets, chainAdapterManager, getChainIdFromEthNetwork, load, setEthNetwork, state.wallet],
[assets, getChainIdFromEthNetwork, load, setEthNetwork, state.wallet],
)

const currentChainNativeAssetId = useMemo(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { btcAssetId, cosmosAssetId } from '@shapeshiftoss/caip'
import { FeeDataKey } from '@shapeshiftoss/chain-adapters'
import { KnownChainIds } from '@shapeshiftoss/types'
import { act, renderHook, waitFor } from '@testing-library/react'
import { mocked } from 'jest-mock'
import type { PropsWithChildren } from 'react'
import { useFormContext, useWatch } from 'react-hook-form'
import { useHistory } from 'react-router-dom'
import { ethereum as mockEthereum, rune as mockRune } from 'test/mocks/assets'
import { TestProviders } from 'test/TestProviders'
import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton'
import { useWallet } from 'hooks/useWallet/useWallet'
import { ensLookup } from 'lib/address/ens'
import { fromBaseUnit } from 'lib/math'
import { assertGetCosmosSdkChainAdapter } from 'lib/utils/cosmosSdk'
import { assertGetEvmChainAdapter } from 'lib/utils/evm'
import { assertGetUtxoChainAdapter } from 'lib/utils/utxo'
import type { AssetBalancesById } from 'state/slices/portfolioSlice/portfolioSliceCommon'
import {
selectFeeAssetById,
Expand All @@ -35,7 +36,9 @@ jest.mock('react-hook-form')
jest.mock('react-router-dom', () => ({ useHistory: jest.fn() }))
jest.mock('hooks/useWallet/useWallet')
jest.mock('context/PluginProvider/PluginProvider')
jest.mock('context/PluginProvider/chainAdapterSingleton')
jest.mock('lib/utils/cosmosSdk')
jest.mock('lib/utils/evm')
jest.mock('lib/utils/utxo')
jest.mock('lib/address/ens', () => ({ ensLookup: jest.fn() }))

jest.mock('state/slices/selectors', () => ({
Expand Down Expand Up @@ -141,14 +144,11 @@ describe('useSendDetails', () => {
beforeEach(() => {
;(useWallet as jest.Mock<unknown>).mockImplementation(() => ({ state: { wallet: {} } }))
;(useHistory as jest.Mock<unknown>).mockImplementation(() => ({ push: jest.fn() }))
;(getChainAdapterManager as jest.Mock<unknown>).mockImplementation(
() =>
new Map([
[KnownChainIds.BitcoinMainnet, mockAdapterBtc],
[KnownChainIds.CosmosMainnet, mockAdapterAtom],
[KnownChainIds.EthereumMainnet, mockAdapterEth],
]),
;(assertGetCosmosSdkChainAdapter as jest.Mock<unknown>).mockImplementation(
() => mockAdapterAtom,
)
;(assertGetEvmChainAdapter as jest.Mock<unknown>).mockImplementation(() => mockAdapterEth)
;(assertGetUtxoChainAdapter as jest.Mock<unknown>).mockImplementation(() => mockAdapterBtc)
;(ensLookup as unknown as jest.Mock<unknown>).mockImplementation(() => ({
address: '0x05A1ff0a32bc24265BCB39499d0c5D9A6cb2011c',
error: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import type { ChainId } from '@shapeshiftoss/caip'
import { CHAIN_NAMESPACE, fromAccountId, fromAssetId } from '@shapeshiftoss/caip'
import type {
CosmosSdkChainId,
EvmBaseAdapter,
EvmChainId,
FeeDataEstimate,
GetFeeDataInput,
UtxoBaseAdapter,
UtxoChainId,
} from '@shapeshiftoss/chain-adapters'
import { debounce } from 'lodash'
Expand All @@ -19,6 +17,9 @@ import { useWallet } from 'hooks/useWallet/useWallet'
import type { BigNumber } from 'lib/bignumber/bignumber'
import { bn, bnOrZero } from 'lib/bignumber/bignumber'
import { tokenOrUndefined } from 'lib/utils'
import { assertGetCosmosSdkChainAdapter } from 'lib/utils/cosmosSdk'
import { assertGetEvmChainAdapter } from 'lib/utils/evm'
import { assertGetUtxoChainAdapter } from 'lib/utils/utxo'
import {
selectAssetById,
selectFeeAssetById,
Expand Down Expand Up @@ -225,19 +226,18 @@ export const useSendDetails = (): UseSendDetailsReturnType => {

try {
const { chainId, chainNamespace, account } = fromAccountId(accountId)
const adapter = chainAdapterManager.get(chainId)
if (!adapter) throw new Error(`No adapter available for ${chainId}`)

const { fastFee, adapterFees } = await (async () => {
switch (chainNamespace) {
case CHAIN_NAMESPACE.CosmosSdk: {
const adapter = assertGetCosmosSdkChainAdapter(chainId)
const getFeeDataInput: Partial<GetFeeDataInput<CosmosSdkChainId>> = {}
const adapterFees = await adapter.getFeeData(getFeeDataInput)
const fastFee = adapterFees.fast.txFee
return { adapterFees, fastFee }
}
case CHAIN_NAMESPACE.Evm: {
const evmAdapter = adapter as unknown as EvmBaseAdapter<EvmChainId>
const evmAdapter = assertGetEvmChainAdapter(chainId)
const getFeeDataInput: GetFeeDataInput<EvmChainId> = {
to,
value: assetBalance,
Expand All @@ -249,7 +249,7 @@ export const useSendDetails = (): UseSendDetailsReturnType => {
return { adapterFees, fastFee }
}
case CHAIN_NAMESPACE.Utxo: {
const utxoAdapter = adapter as unknown as UtxoBaseAdapter<UtxoChainId>
const utxoAdapter = assertGetUtxoChainAdapter(chainId)
const getFeeDataInput: GetFeeDataInput<UtxoChainId> = {
to,
value: assetBalance,
Expand Down
42 changes: 18 additions & 24 deletions src/components/Modals/Send/utils.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import type { AssetId, ChainId } from '@shapeshiftoss/caip'
import { CHAIN_NAMESPACE, fromAccountId, fromAssetId, fromChainId } from '@shapeshiftoss/caip'
import type {
ChainAdapter,
CosmosSdkBaseAdapter,
CosmosSdkChainId,
EvmBaseAdapter,
EvmChainId,
FeeData,
FeeDataEstimate,
GetFeeDataInput,
UtxoBaseAdapter,
UtxoChainId,
} from '@shapeshiftoss/chain-adapters'
import { utxoChainIds } from '@shapeshiftoss/chain-adapters'
import type { HDWallet } from '@shapeshiftoss/hdwallet-core'
import { supportsETH } from '@shapeshiftoss/hdwallet-core'
import type { KnownChainIds } from '@shapeshiftoss/types'
import { getChainAdapterManager } from 'context/PluginProvider/chainAdapterSingleton'
import { getSupportedEvmChainIds } from 'hooks/useEvm/useEvm'
import { checkIsMetaMask, checkIsSnapInstalled } from 'hooks/useIsSnapInstalled/useIsSnapInstalled'
import { bn, bnOrZero } from 'lib/bignumber/bignumber'
import { tokenOrUndefined } from 'lib/utils'
import { assertGetChainAdapter, tokenOrUndefined } from 'lib/utils'
import { assertGetCosmosSdkChainAdapter } from 'lib/utils/cosmosSdk'
import { assertGetEvmChainAdapter } from 'lib/utils/evm'
import { assertGetUtxoChainAdapter } from 'lib/utils/utxo'
import { selectAssetById, selectPortfolioAccountMetadataByAccountId } from 'state/slices/selectors'
import { store } from 'state/store'

Expand Down Expand Up @@ -49,26 +46,22 @@ export const estimateFees = ({
accountId,
contractAddress,
}: EstimateFeesInput): Promise<FeeDataEstimate<ChainId>> => {
const chainAdapterManager = getChainAdapterManager()
const { account } = fromAccountId(accountId)
const state = store.getState()
const asset = selectAssetById(state, assetId)
if (!asset) throw new Error(`Asset not found for ${assetId}`)
const value = bnOrZero(cryptoAmount).times(bn(10).exponentiatedBy(asset.precision)).toFixed(0)

const adapter = chainAdapterManager.get(asset.chainId)
if (!adapter) throw new Error(`No adapter available for ${asset.chainId}`)

const { chainNamespace } = fromChainId(asset.chainId)

switch (chainNamespace) {
case CHAIN_NAMESPACE.CosmosSdk: {
const adapter = assertGetCosmosSdkChainAdapter(asset.chainId)
const getFeeDataInput: Partial<GetFeeDataInput<CosmosSdkChainId>> = {}
return (adapter as unknown as CosmosSdkBaseAdapter<CosmosSdkChainId>).getFeeData(
getFeeDataInput,
)
return adapter.getFeeData(getFeeDataInput)
}
case CHAIN_NAMESPACE.Evm: {
const adapter = assertGetEvmChainAdapter(asset.chainId)
const getFeeDataInput: GetFeeDataInput<EvmChainId> = {
to,
value,
Expand All @@ -79,16 +72,17 @@ export const estimateFees = ({
},
sendMax,
}
return (adapter as unknown as EvmBaseAdapter<EvmChainId>).getFeeData(getFeeDataInput)
return adapter.getFeeData(getFeeDataInput)
}
case CHAIN_NAMESPACE.Utxo: {
const adapter = assertGetUtxoChainAdapter(asset.chainId)
const getFeeDataInput: GetFeeDataInput<UtxoChainId> = {
to,
value,
chainSpecific: { from, pubkey: account },
sendMax,
}
return (adapter as unknown as UtxoBaseAdapter<UtxoChainId>).getFeeData(getFeeDataInput)
return adapter.getFeeData(getFeeDataInput)
}
default:
throw new Error(`${chainNamespace} not supported`)
Expand All @@ -102,7 +96,6 @@ export const handleSend = async ({
sendInput: SendInput
wallet: HDWallet
}): Promise<string> => {
const chainAdapterManager = getChainAdapterManager()
const supportedEvmChainIds = getSupportedEvmChainIds()

const state = store.getState()
Expand All @@ -119,14 +112,11 @@ export const handleSend = async ({
throw new Error(`unsupported wallet: ${await wallet.getModel()}`)
}

const adapter = chainAdapterManager.get(asset.chainId) as ChainAdapter<KnownChainIds>
if (!adapter) throw new Error(`useFormSend: no adapter available for ${asset.chainId}`)

const value = bnOrZero(sendInput.cryptoAmount)
.times(bn(10).exponentiatedBy(asset.precision))
.toFixed(0)

const chainId = adapter.getChainId()
const chainId = asset.chainId

const { estimatedFees, feeType, to, memo, from } = sendInput

Expand All @@ -153,7 +143,8 @@ export const handleSend = async ({
}
const contractAddress = tokenOrUndefined(fromAssetId(asset.assetId).assetReference)
const { accountNumber } = bip44Params
return await (adapter as unknown as EvmBaseAdapter<EvmChainId>).buildSendTransaction({
const adapter = assertGetEvmChainAdapter(chainId)
return await adapter.buildSendTransaction({
to,
value,
wallet,
Expand All @@ -178,7 +169,8 @@ export const handleSend = async ({
)
}
const { accountNumber } = bip44Params
return (adapter as unknown as UtxoBaseAdapter<UtxoChainId>).buildSendTransaction({
const adapter = assertGetUtxoChainAdapter(chainId)
return adapter.buildSendTransaction({
to,
value,
wallet,
Expand All @@ -205,7 +197,7 @@ export const handleSend = async ({
chainSpecific: { gas: fees.chainSpecific.gasLimit, fee: fees.txFee },
sendMax: sendInput.sendMax,
}

const adapter = assertGetCosmosSdkChainAdapter(chainId)
return adapter.buildSendTransaction(params)
}

Expand All @@ -214,6 +206,8 @@ export const handleSend = async ({

const txToSign = result.txToSign

const adapter = assertGetChainAdapter(chainId)

const senderAddress = await adapter.getAddress({
accountNumber: accountMetadata.bip44Params.accountNumber,
accountType: accountMetadata.accountType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CheckCircleIcon } from '@chakra-ui/icons'
import { Button, Card, CardBody, Link, VStack } from '@chakra-ui/react'
import { Button, Card, CardBody, Link, Tooltip, VStack } from '@chakra-ui/react'
import type { SwapperName, TradeQuoteStep } from '@shapeshiftoss/swapper'
import type { KnownChainIds } from '@shapeshiftoss/types'
import type Polyglot from 'node-polyglot'
Expand Down Expand Up @@ -45,7 +45,7 @@ export const HopTransactionStep = ({
const translate = useTranslate()

const {
swap: { state: swapTxState, sellTxHash, buyTxHash },
swap: { state: swapTxState, sellTxHash, buyTxHash, message },
} = useAppSelector(state => selectHopExecutionMetadata(state, hopIndex))

const isError = useMemo(() => swapTxState === TransactionExecutionState.Failed, [swapTxState])
Expand Down Expand Up @@ -168,6 +168,11 @@ export const HopTransactionStep = ({
{`${sellAmountCryptoFormatted}.${sellChainSymbol} -> ${buyAmountCryptoFormatted}.${buyChainSymbol}`}
</RawText>
{isError && <Text color='text.error' translation={errorTranslation} fontWeight='bold' />}
{Boolean(message) && (
<Tooltip label={message}>
<RawText color='text.subtle'>{message}</RawText>
</Tooltip>
)}
{txLink && (
<Link isExternal color='text.link' href={txLink}>
<MiddleEllipsis value={txHash} />
Expand All @@ -178,6 +183,7 @@ export const HopTransactionStep = ({
}, [
errorTranslation,
isError,
message,
toCrypto,
tradeQuoteStep.buyAmountBeforeFeesCryptoBaseUnit,
tradeQuoteStep.buyAsset.chainId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ export const useTradeExecution = (hopIndex: number) => {
dispatch(tradeQuoteSlice.actions.setSwapTxPending({ hopIndex }))

const onFail = (e: unknown) => {
const { message } = (e ?? { message: undefined }) as { message?: string }
dispatch(tradeQuoteSlice.actions.setSwapTxMessage({ hopIndex, message }))
dispatch(tradeQuoteSlice.actions.setSwapTxFailed({ hopIndex }))
showErrorToast(e)
resolve()
Expand All @@ -71,10 +73,12 @@ export const useTradeExecution = (hopIndex: number) => {
execution.on(TradeExecutionEvent.SellTxHash, ({ sellTxHash }) => {
dispatch(tradeQuoteSlice.actions.setSwapSellTxHash({ hopIndex, sellTxHash }))
})
execution.on(TradeExecutionEvent.Status, ({ buyTxHash }) => {
execution.on(TradeExecutionEvent.Status, ({ buyTxHash, message }) => {
dispatch(tradeQuoteSlice.actions.setSwapTxMessage({ hopIndex, message }))
buyTxHash && tradeQuoteSlice.actions.setSwapBuyTxHash({ hopIndex, buyTxHash })
})
execution.on(TradeExecutionEvent.Success, () => {
dispatch(tradeQuoteSlice.actions.setSwapTxMessage({ hopIndex, message: undefined }))
dispatch(tradeQuoteSlice.actions.setSwapTxComplete({ hopIndex }))
resolve()
})
Expand Down
Loading

0 comments on commit b2cf2e7

Please sign in to comment.