Skip to content

Commit

Permalink
feat: network requests (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
gomesalexandre authored Jan 29, 2025
1 parent 0ddbe4b commit a95eba2
Show file tree
Hide file tree
Showing 18 changed files with 664 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ VITE_FOO=bar
# chat woot
VITE_CHATWOOT_TOKEN=jmoXp9BPMSPEYHeJX5YKT15Q
VITE_CHATWOOT_URL=https://app.chatwoot.com

# Chainflip

VITE_CHAINFLIP_API_KEY=09bc0796ff40435482c0a54fa6ae2784
VITE_CHAINFLIP_API_URL=https://chainflip-broker.io
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
"@chakra-ui/react": "^2.10.3",
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
"@lukemorales/query-key-factory": "^1.3.4",
"@shapeshiftoss/caip": "^8.15.0",
"@shapeshiftoss/types": "^8.6.0",
"@tanstack/react-query": "^5.65.1",
"axios": "^1.6.5",
"framer-motion": "^10.17.9",
"match-sorter": "^6.3.1",
Expand Down
13 changes: 9 additions & 4 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import './App.css'

import { Center } from '@chakra-ui/react'
import { QueryClientProvider } from '@tanstack/react-query'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { ChatwootButton } from 'components/Chatwoot'
import { SelectPair } from 'components/SelectPair'
import { Status } from 'components/Status/Status'
import { TradeInput } from 'components/TradeInput'

import { queryClient } from './config/react-query'

const router = createBrowserRouter([
{
path: '/',
Expand All @@ -26,10 +29,12 @@ function App() {
console.log(import.meta.env.VITE_FOO)

return (
<Center width='full' height='100vh' flexDir='column'>
<RouterProvider router={router} />
<ChatwootButton />
</Center>
<QueryClientProvider client={queryClient}>
<Center width='full' height='100vh' flexDir='column'>
<RouterProvider router={router} />
<ChatwootButton />
</Center>
</QueryClientProvider>
)
}

Expand Down
3 changes: 3 additions & 0 deletions src/config/react-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { QueryClient } from '@tanstack/react-query'

export const queryClient = new QueryClient()
60 changes: 60 additions & 0 deletions src/constants/caip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Subset of web caip constants with Chainflip-supported assets only
// We need to redeclare things here as @shapeshiftoss/caip is actually a monorepo project and not published on npm

import type { AssetId, ChainId } from '@shapeshiftoss/caip'

export const btcAssetId: AssetId = 'bip122:000000000019d6689c085ae165831e93/slip44:0'

export const ethAssetId: AssetId = 'eip155:1/slip44:60'
export const arbitrumAssetId: AssetId = 'eip155:42161/slip44:60'
export const solAssetId: AssetId = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501'
export const wrappedSolAssetId: AssetId =
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:So11111111111111111111111111111111111111112'
export const usdtAssetId: AssetId = 'eip155:1/erc20:0xdac17f958d2ee523a2206206994597c13d831ec7'
export const usdcAssetId: AssetId = 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
export const usdcOnArbitrumOneAssetId: AssetId =
'eip155:42161/erc20:0xaf88d065e77c8cc2239327c5edb3a432268e5831'
export const usdcOnSolanaAssetId: AssetId =
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/token:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
export const flipAssetId: AssetId = 'eip155:1/erc20:0x826180541412d574cf1336d22c0c0a287822678a'

export const btcChainId: ChainId = 'bip122:000000000019d6689c085ae165831e93'

export const ethChainId: ChainId = 'eip155:1'
export const arbitrumChainId: ChainId = 'eip155:42161'
export const baseChainId: ChainId = 'eip155:8453'

export const solanaChainId: ChainId = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'

export const CHAIN_NAMESPACE = {
Evm: 'eip155',
Utxo: 'bip122',
CosmosSdk: 'cosmos',
Solana: 'solana',
} as const

export const CHAIN_REFERENCE = {
EthereumMainnet: '1',
BitcoinMainnet: '000000000019d6689c085ae165831e93',
ArbitrumMainnet: '42161',
ArbitrumNovaMainnet: '42170',
BaseMainnet: '8453',
SolanaMainnet: '5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
} as const

export const ASSET_NAMESPACE = {
erc20: 'erc20',
erc721: 'erc721',
erc1155: 'erc1155',
slip44: 'slip44',
splToken: 'token',
} as const

export const ASSET_REFERENCE = {
Bitcoin: '0',
Ethereum: '60',
Arbitrum: '60', // evm chain which uses ethereum derivation path as common practice
Solana: '501',
} as const

export const FEE_ASSET_IDS = [ethAssetId, btcAssetId, arbitrumAssetId, solAssetId]
2 changes: 2 additions & 0 deletions src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ interface ImportMetaEnv {
readonly VITE_CHATWOOT_URL: string
readonly VITE_CHATWOOT_TOKEN: string
readonly VITE_FEATURE_CHATWOOT: boolean
readonly VITE_CHAINFLIP_API_KEY: string
readonly VITE_CHAINFLIP_API_URL: string
}

interface ImportMeta {
Expand Down
91 changes: 91 additions & 0 deletions src/queries/chainflip/assets.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { btcAssetId, ethAssetId, usdcOnSolanaAssetId } from 'constants/caip'
import { describe, expect, it } from 'vitest'

import { transformChainflipAssets } from './assets'
import type { ChainflipAssetsResponse } from './types'

describe('transformChainflipAssets', () => {
it('should transform multiple chainflip assets to assetIds', () => {
const mockResponse: ChainflipAssetsResponse = {
assets: [
{
id: 'btc.btc',
direction: 'both',
ticker: 'BTC',
name: 'Bitcoin',
network: 'Bitcoin',
networkLogo: '/networks/btc/logo.svg',
assetLogo: '/assets/btc.btc/logo.svg',
decimals: 8,
minimalAmount: 0.0007,
minimalAmountNative: '70000',
usdPrice: 102680.1024594243,
usdPriceNative: '102680102459',
},
{
id: 'eth.eth',
direction: 'both',
ticker: 'ETH',
name: 'Ethereum',
network: 'Ethereum',
networkLogo: '/networks/eth/logo.svg',
assetLogo: '/assets/eth.eth/logo.svg',
decimals: 18,
minimalAmount: 0.01,
minimalAmountNative: '10000000000000000',
usdPrice: 3175.43595522135,
usdPriceNative: '3175435955',
},
],
}

expect(transformChainflipAssets(mockResponse)).toEqual([btcAssetId, ethAssetId])
})

it('should transform single chainflip asset to assetId', () => {
const mockResponse: ChainflipAssetsResponse = {
assets: [
{
id: 'usdc.sol',
direction: 'both',
ticker: 'USDC',
name: 'solUSDC',
network: 'Solana',
contractAddress: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
networkLogo: '/networks/sol/logo.svg',
assetLogo: '/assets/usdc.sol/logo.svg',
decimals: 6,
minimalAmount: 10,
minimalAmountNative: '10000000',
usdPrice: 1.0014781977,
usdPriceNative: '1001478',
},
],
}

expect(transformChainflipAssets(mockResponse)).toEqual([usdcOnSolanaAssetId])
})

it('should return empty array for unsupported assets', () => {
const mockResponse: ChainflipAssetsResponse = {
assets: [
{
id: 'unsupported.asset',
direction: 'both',
ticker: 'UNSUPPORTED',
name: 'Unsupported Asset',
network: 'Unknown',
networkLogo: '/networks/unknown/logo.svg',
assetLogo: '/assets/unknown.asset/logo.svg',
decimals: 18,
minimalAmount: 1,
minimalAmountNative: '1000000000000000000',
usdPrice: 1,
usdPriceNative: '1000000000000000000',
},
],
}

expect(transformChainflipAssets(mockResponse)).toEqual([])
})
})
39 changes: 39 additions & 0 deletions src/queries/chainflip/assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useQuery } from '@tanstack/react-query'
import {
arbitrumAssetId,
btcAssetId,
ethAssetId,
flipAssetId,
solAssetId,
usdcAssetId,
usdcOnArbitrumOneAssetId,
usdcOnSolanaAssetId,
usdtAssetId,
} from 'constants/caip'

import { reactQueries } from '../react-queries'
import type { ChainflipAssetsResponse } from './types'

// Map Chainflip internal asset IDs to CAIPs
const chainflipToAssetId: Record<string, string> = {
'btc.btc': btcAssetId,
'eth.arb': arbitrumAssetId,
'eth.eth': ethAssetId,
'flip.eth': flipAssetId,
'sol.sol': solAssetId,
'usdc.arb': usdcOnArbitrumOneAssetId,
'usdc.eth': usdcAssetId,
'usdc.sol': usdcOnSolanaAssetId,
'usdt.eth': usdtAssetId,
}

export const transformChainflipAssets = (data: ChainflipAssetsResponse) => {
return data.assets.map(asset => chainflipToAssetId[asset.id]).filter(Boolean)
}

export const useChainflipAssetsQuery = () => {
return useQuery({
...reactQueries.chainflip.assets,
select: transformChainflipAssets,
})
}
10 changes: 10 additions & 0 deletions src/queries/chainflip/quote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useQuery } from '@tanstack/react-query'

import { reactQueries } from '../react-queries'
import type { ChainflipQuoteParams } from './types'

export const useChainflipQuoteQuery = (params: ChainflipQuoteParams) => {
return useQuery({
...reactQueries.chainflip.quote(params),
})
}
16 changes: 16 additions & 0 deletions src/queries/chainflip/status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useQuery } from '@tanstack/react-query'

import { reactQueries } from '../react-queries'

type ChainflipStatusQueryParams = {
swapId: number
enabled?: boolean
}

export const useChainflipStatusQuery = ({ swapId, enabled = true }: ChainflipStatusQueryParams) => {
return useQuery({
...reactQueries.chainflip.status(swapId),
refetchInterval: 15000,
enabled,
})
}
10 changes: 10 additions & 0 deletions src/queries/chainflip/swap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useQuery } from '@tanstack/react-query'

import { reactQueries } from '../react-queries'
import type { ChainflipSwapParams } from './types'

export const useChainflipSwapQuery = (params: ChainflipSwapParams) => {
return useQuery({
...reactQueries.chainflip.swap(params),
})
}
Loading

0 comments on commit a95eba2

Please sign in to comment.