diff --git a/batcher-ui/src/actions/exchange.ts b/batcher-ui/src/actions/exchange.ts index aef4b733..69c38f2a 100644 --- a/batcher-ui/src/actions/exchange.ts +++ b/batcher-ui/src/actions/exchange.ts @@ -1,27 +1,27 @@ -import { BatcherStatus, CurrentSwap, PriceStrategy } from '@/types'; +import { BatcherStatus, CurrentSwap, PriceStrategy, Token } from '@/types'; export const updatePriceStrategy = (priceStrategy: PriceStrategy) => ({ type: 'UDPATE_PRICE_STATEGY', payload: { priceStrategy }, - } as const); + }) as const; export const reverseSwap = () => ({ type: 'REVERSE_SWAP', - } as const); + }) as const; export const changePair = (pair: string, isReverse: boolean) => ({ type: 'CHANGE_PAIR', payload: { pair, isReverse }, - } as const); + }) as const; export const getPairsInfos = (pair: string) => ({ type: 'GET_PAIR_INFOS', payload: { pair }, - } as const); + }) as const; export const updatePairsInfos = ({ currentSwap, @@ -33,12 +33,12 @@ export const updatePairsInfos = ({ ({ type: 'UPDATE_PAIR_INFOS', payload: { currentSwap, pair }, - } as const); + }) as const; export const getBatcherStatus = () => ({ type: 'GET_BATCHER_STATUS', - } as const); + }) as const; export const updateBatcherStatus = ({ status, @@ -52,62 +52,72 @@ export const updateBatcherStatus = ({ ({ type: 'UDPATE_BATCHER_STATUS', payload: { status, at, startTime }, - } as const); + }) as const; export const updateRemainingTime = () => ({ type: 'UPDATE_REMAINING_TIME', - } as const); + }) as const; export const getCurrentBatchNumber = () => ({ type: 'GET_CURRENT_BATCHER_NUMBER', - } as const); + }) as const; export const updateBatchNumber = (batchNumber: number) => ({ type: 'UDPATE_BATCH_NUMBER', payload: { batchNumber }, - } as const); + }) as const; export const batcherSetup = () => ({ type: 'BATCHER_SETUP', - } as const); + }) as const; export const batcherTimerId = (timerId: number) => ({ type: 'BATCHER_TIMER_ID', payload: { timerId }, - } as const); + }) as const; export const batcherUnsetup = () => ({ type: 'BATCHER_UNSETUP', - } as const); + }) as const; export const getOraclePrice = () => ({ type: 'GET_ORACLE_PRICE', - } as const); + }) as const; export const updateOraclePrice = (oraclePrice: number) => ({ type: 'UPDATE_ORACLE_PRICE', payload: { oraclePrice }, - } as const); + }) as const; export const getVolumes = () => ({ type: 'GET_VOLUMES', - } as const); + }) as const; export const updateVolumes = (volumes: unknown) => ({ type: 'UPDATE_VOLUMES', payload: { volumes }, - } as const); + }) as const; +export const updateTokens = (tokens: Map) => + ({ + type: 'UPDATE_TOKENS', + payload: { tokens }, + }) as const; + +export const getTokens = () => + ({ + type: 'GET_TOKENS', + }) as const; export type ExchangeActions = | ReturnType @@ -126,4 +136,6 @@ export type ExchangeActions = | ReturnType | ReturnType | ReturnType - | ReturnType; + | ReturnType + | ReturnType + | ReturnType; diff --git a/batcher-ui/src/actions/index.ts b/batcher-ui/src/actions/index.ts index e852d61b..e113b0f0 100644 --- a/batcher-ui/src/actions/index.ts +++ b/batcher-ui/src/actions/index.ts @@ -4,14 +4,12 @@ import { EventActions } from './events'; import { HoldingsActions } from './holdings'; import { MarketHoldingsActions } from './marketholdings'; - export * from './wallet'; export * from './exchange'; export * from './events'; export * from './holdings'; export * from './marketholdings'; - export type Actions = | WalletActions | ExchangeActions diff --git a/batcher-ui/src/commands/events.ts b/batcher-ui/src/commands/events.ts index 42a5946b..3136872f 100644 --- a/batcher-ui/src/commands/events.ts +++ b/batcher-ui/src/commands/events.ts @@ -64,6 +64,7 @@ export const newEventCmd = (event: BigMapEvent) => { case 'rates_current': { //! oracle price has changed const data = eventData.content.value as RatesCurrentBigmap; + console.info("Oracle change",data); dispatch( updateOraclePrice( computeOraclePrice(data.rate, { diff --git a/batcher-ui/src/commands/exchange.ts b/batcher-ui/src/commands/exchange.ts index 2f215d74..2028ef8c 100644 --- a/batcher-ui/src/commands/exchange.ts +++ b/batcher-ui/src/commands/exchange.ts @@ -6,6 +6,7 @@ import { getCurrentRates, getVolumes, getTimeDifferenceInMs, + getTokens, } from '@/utils/utils'; import { getPairsInformation } from '@/utils/token-manager'; import { @@ -17,8 +18,9 @@ import { batcherTimerId, updateRemainingTime, newError, + updateTokens, } from '@/actions'; -import { BatcherStatus, CurrentSwap, SwapNames } from '@/types'; +import { BatcherStatus, CurrentSwap, SwapNames, Token } from '@/types'; const fetchPairInfosCmd = (pair: string) => Cmd.run( @@ -93,10 +95,10 @@ const fetchOraclePriceCmd = (tokenPair: string, { swap }: CurrentSwap) => { ); }; -const fetchVolumesCmd = (batchNumber: number) => { +const fetchVolumesCmd = (batchNumber: number, tokens:Map) => { return Cmd.run( () => { - return getVolumes(batchNumber); + return getVolumes(batchNumber,tokens); }, { successActionCreator: updateVolumes, @@ -105,6 +107,19 @@ const fetchVolumesCmd = (batchNumber: number) => { ); }; +const fetchTokensCmd = () => { + return Cmd.run( + async () => { + const tokens = await getTokens(); + + return tokens; + }, + { + successActionCreator: updateTokens, + failActionCreator: (e: string) => newError(e), + } + ); +}; export { fetchPairInfosCmd, fetchCurrentBatchNumberCmd, @@ -112,4 +127,5 @@ export { setupBatcherCmd, fetchOraclePriceCmd, fetchVolumesCmd, + fetchTokensCmd, }; diff --git a/batcher-ui/src/pages/index.tsx b/batcher-ui/src/pages/index.tsx index 752235c6..c42444a9 100644 --- a/batcher-ui/src/pages/index.tsx +++ b/batcher-ui/src/pages/index.tsx @@ -4,12 +4,22 @@ import BatcherInfo from '@/components/batcher/BatcherInfo'; import PriceStrategy from '@/components/batcher/PriceStrategy'; import { useSelector, useDispatch } from 'react-redux'; -import { currentPairSelector, userAddressSelector } from '@/reducers'; -import { fetchUserBalances, batcherUnsetup, getPairsInfos } from '@/actions'; +import { + currentPairSelector, + userAddressSelector, + tokensSelector, +} from '@/reducers'; +import { + getTokens, + fetchUserBalances, + batcherUnsetup, + getPairsInfos, +} from '@/actions'; const Swap = () => { const userAddress = useSelector(userAddressSelector); const tokenPair = useSelector(currentPairSelector); + const tokens = useSelector(tokensSelector); const dispatch = useDispatch(); @@ -27,6 +37,10 @@ const Swap = () => { } }, [userAddress, dispatch]); + useEffect(() => { + dispatch(getTokens()); + }, [ dispatch]); + return (
diff --git a/batcher-ui/src/pages/volumes.tsx b/batcher-ui/src/pages/volumes.tsx index aa14ba80..57f27b26 100644 --- a/batcher-ui/src/pages/volumes.tsx +++ b/batcher-ui/src/pages/volumes.tsx @@ -1,18 +1,24 @@ import React, { useEffect } from 'react'; import { PriceStrategy } from '@/types'; -import { batchNumberSelector, volumesSelector } from '@/reducers'; +import { + batchNumberSelector, + volumesSelector, + tokensSelector, +} from '@/reducers'; import { useSelector } from 'react-redux'; import { useDispatch } from 'react-redux'; import { getVolumes } from '@/actions'; +import { batch } from 'react-redux'; const Volume = () => { const { sell, buy } = useSelector(volumesSelector); const batchNumber = useSelector(batchNumberSelector); + const tokens = useSelector(tokensSelector); const dispatch = useDispatch(); useEffect(() => { if (batchNumber) dispatch(getVolumes()); - }, [dispatch, batchNumber]); + }, [dispatch, batchNumber, tokens]); const listOfBuyVolumesColumns = [ { @@ -58,7 +64,8 @@ const Volume = () => { {listOfBuyVolumesColumns.map((b, i) => ( + key={i} + > {b.title} ))} @@ -70,7 +77,8 @@ const Volume = () => { return ( + key={i} + > {buy[b.key]} ); @@ -82,7 +90,8 @@ const Volume = () => { {listOfSellVolumesColumns.map((b, i) => ( + key={i} + > {b.title} ))} @@ -94,7 +103,8 @@ const Volume = () => { return ( + key={i} + > {sell[b.key]} ); diff --git a/batcher-ui/src/reducers/exchange.ts b/batcher-ui/src/reducers/exchange.ts index f7a51038..b05da888 100644 --- a/batcher-ui/src/reducers/exchange.ts +++ b/batcher-ui/src/reducers/exchange.ts @@ -5,13 +5,14 @@ import { getCurrentBatchNumber, getOraclePrice, getPairsInfos, -} from '../../src/actions'; +} from '@/actions'; import { BatcherStatus, CurrentSwap, ExchangeState, PriceStrategy, -} from '../../src/types'; + Token, +} from '@/types'; import { fetchBatcherStatusCmd, fetchCurrentBatchNumberCmd, @@ -19,7 +20,8 @@ import { fetchVolumesCmd, fetchOraclePriceCmd, setupBatcherCmd, -} from '../../src/commands/exchange'; + fetchTokensCmd, +} from '@/commands/exchange'; import { getTimeDifference } from 'src/utils/utils'; const initialSwap: CurrentSwap = { @@ -55,9 +57,10 @@ const initialState: ExchangeState = { startTime: null, remainingTime: 0, }, - swapPairName: 'tzBTC/USDT', + swapPairName: 'tzBTC-USDT', batchNumber: 0, oraclePrice: 0, + tokens: new Map(), volumes: { sell: Object.keys(PriceStrategy).reduce( (acc, k) => ({ ...acc, [k]: 0 }), @@ -193,9 +196,13 @@ const exchangeReducer = ( case 'UPDATE_ORACLE_PRICE': return { ...state, oraclePrice: action.payload.oraclePrice }; case 'GET_VOLUMES': - return loop(state, fetchVolumesCmd(state.batchNumber)); + return loop(state, fetchVolumesCmd(state.batchNumber, state.tokens)); case 'UPDATE_VOLUMES': return { ...state, volumes: action.payload.volumes }; + case 'UPDATE_TOKENS': + return { ...state, tokens: action.payload.tokens }; + case 'GET_TOKENS': + return loop(state, fetchTokensCmd()); default: return state; } diff --git a/batcher-ui/src/reducers/index.ts b/batcher-ui/src/reducers/index.ts index d388712c..b7b75011 100644 --- a/batcher-ui/src/reducers/index.ts +++ b/batcher-ui/src/reducers/index.ts @@ -8,6 +8,7 @@ import { MarketHoldingsState, EventsState, HoldingsState, + TokensState, } from '../types'; import { marketHoldingsReducer } from '@/reducers/marketholdings'; import { eventReducer } from '@/reducers/events'; @@ -49,6 +50,8 @@ export const batchNumberSelector = (state: AppState) => export const oraclePriceSelector = (state: AppState) => state.exchange.oraclePrice; +export const tokensSelector = (state: AppState) => state.exchange.tokens; + export const volumesSelector = (state: AppState) => state.exchange.volumes; // Holdings selectors diff --git a/batcher-ui/src/types/state.ts b/batcher-ui/src/types/state.ts index 659f8385..223c9bfc 100644 --- a/batcher-ui/src/types/state.ts +++ b/batcher-ui/src/types/state.ts @@ -29,6 +29,7 @@ export type VolumesState = { sell: Record; }; + export type ExchangeState = { priceStrategy: PriceStrategy; currentSwap: CurrentSwap; @@ -43,6 +44,7 @@ export type ExchangeState = { batchNumber: number; oraclePrice: number; volumes: VolumesState; + tokens: Map; }; export type WalletState = { @@ -76,7 +78,7 @@ export type GlobalVault = { }; export type MarketHoldingsState = { - vault_address: string, + vault_address: string; shares: number; nativeToken: ValidTokenAmount | undefined; foreignTokens: Array; diff --git a/batcher-ui/src/utils/token-manager.ts b/batcher-ui/src/utils/token-manager.ts index cfcb3f47..19b3c480 100644 --- a/batcher-ui/src/utils/token-manager.ts +++ b/batcher-ui/src/utils/token-manager.ts @@ -7,9 +7,6 @@ import { ValidTokenAmount, } from '@/types'; import { checkStatus, scaleAmountDown } from '@/utils/utils'; -import * as api from '@tzkt/sdk-api'; - -api.defaults.baseUrl = `${process.env.NEXT_PUBLIC_TZKT_API_URI}`; export const getTokenManagerStorage = (): Promise => fetch( @@ -32,32 +29,6 @@ const getSwapFromBigmap = ( `${process.env.NEXT_PUBLIC_TZKT_API_URI}/v1/bigmaps/${bigMapId}/keys/${swapName}` ).then(checkStatus); -export const getTokensMetadata = async () => { - const storage = await getTokenManagerStorage(); - const validTokens = storage['valid_tokens']; - const names = validTokens.keys; - return Promise.all( - names.map(async token => { - const t = await getTokenFromBigmap(validTokens.values, token); - const icon = await fetch( - `${process.env.NEXT_PUBLIC_TZKT_API_URI}/v1/tokens?contract=${t.value.address}` - ) - .then(t => t.json()) - .then(([t]) => - t?.metadata?.thumbnailUri - ? `https://ipfs.io/ipfs/${t.metadata.thumbnailUri.split('//')[1]}` - : undefined - ); - - return { - name: t.value.name, - address: t.value.address, - icon, - }; - }) - ); -}; - export const getLexicographicalPairName = ( to: string, from: string @@ -73,7 +44,6 @@ export const getSwapsMetadata = async () => { const storage = await getTokenManagerStorage(); const validSwaps = storage['valid_swaps']; const names = validSwaps.keys; - const bm = await api.bigMapsGetBigMapById(validSwaps.values); return Promise.all( names.map(async swap => { const escapedPair = encodeURIComponent(swap); @@ -182,3 +152,48 @@ export const parseTokenAmount = (tokenAmountObject: any): ValidTokenAmount => { }; } }; +export const getTokensMetadata = async () => { + const storage = await getTokenManagerStorage(); + const validTokens = storage['valid_tokens']; + const names = validTokens.keys; + return Promise.all( + names.map(async token => { + const t = await getTokenFromBigmap(validTokens.values, token); + const icon = await fetch( + `${process.env.NEXT_PUBLIC_TZKT_API_URI}/v1/tokens?contract=${t.value.address}` + ) + .then(t => t.json()) + .then(([t]) => + t?.metadata?.thumbnailUri + ? `https://ipfs.io/ipfs/${t.metadata.thumbnailUri.split('//')[1]}` + : undefined + ); + + return { + name: t.value.name, + address: t.value.address, + icon, + }; + }) + ); +}; + + +export const getTokensFromStorage = async () => { + const storage = await getTokenManagerStorage(); + const validTokens = storage['valid_tokens']; + const names = validTokens.keys; + return Promise.all( + names.map(async token => { + const t = await getTokenFromBigmap(validTokens.values, token); + + return { + name: t.value.name, + address: t.value.address, + decimals: t.value.decimals, + standard: t.value.standard, + tokenId: t.value.token_id, + }; + }) + ); +}; diff --git a/batcher-ui/src/utils/utils.ts b/batcher-ui/src/utils/utils.ts index 297c1520..dc6ec224 100644 --- a/batcher-ui/src/utils/utils.ts +++ b/batcher-ui/src/utils/utils.ts @@ -16,11 +16,26 @@ import { OrderBookBigmap, SwapNames, RatesCurrentBigmap, + Token, } from '@/types'; -import { getTokenManagerStorage } from '@/utils/token-manager'; +import { + getTokenManagerStorage, + getTokensFromStorage, +} from '@/utils/token-manager'; import { NetworkType } from '@airgap/beacon-sdk'; import { getByKey } from '@/utils/local-storage'; +export const getTokens = async () => { + const tokens = await getTokensFromStorage(); + console.info('getTokens tokens', tokens); + const tokenMap = new Map(tokens.map((value, index) => [value.name, value])); + console.info('getTokens tokenMap', tokenMap); + + return { + tokens: tokenMap, + }; +}; + export const scaleAmountDown = (amount: number, decimals: number) => { const scale = 10 ** -decimals; return amount * scale; @@ -406,11 +421,19 @@ export const toVolumes = ( }; }; -export const getVolumes = async (batchNumber: number) => { +export const getVolumes = async ( + batchNumber: number, + tokens: Map +) => { const batch = await getBigMapByIdAndBatchNumber(batchNumber); + const buyTokenName = batch.pair.string_0; + const sellTokenName = batch.pair.string_1; + const toks = Object.values(tokens)[0]; + const buyToken = toks.get(buyTokenName); + const sellToken = toks.get(sellTokenName); return toVolumes(batch['volumes'], { - buyDecimals: parseInt(batch.pair.decimals_0, 10), - sellDecimals: parseInt(batch.pair.decimals_1, 10), + buyDecimals: parseInt(buyToken.decimals, 10), + sellDecimals: parseInt(sellToken.decimals, 10), }); };