diff --git a/src/components/forms/SelectToken.tsx b/src/components/forms/SelectToken.tsx index 57edf1bad..58563cff7 100644 --- a/src/components/forms/SelectToken.tsx +++ b/src/components/forms/SelectToken.tsx @@ -474,6 +474,7 @@ export default function SelectToken({ const [visible, setVisible] = useState(false); const [listData, setListData] = useState([]); const [listTknData, setListTknData] = useState([]); + const [listTknxData, setListTknxData] = useState([]); const [currentSort, setSort] = useState('down'); const [sortBy, setSortBy] = useState('near'); const [showCommonBasses, setShowCommonBasses] = useState(true); @@ -507,7 +508,22 @@ export default function SelectToken({ useTokensData( tokens.filter( (t) => - TOKEN_BLACK_LIST.indexOf(t.id) === -1 && t.isRisk && !t.isUserToken + TOKEN_BLACK_LIST.indexOf(t.id) === -1 && + t.id.indexOf('tknx') == -1 && + t.isRisk && + !t.isUserToken + ), + balances, + visible + ); + const { tokensData: tknxTokensData, loading: loadingTKNXTokensData } = + useTokensData( + tokens.filter( + (t) => + TOKEN_BLACK_LIST.indexOf(t.id) === -1 && + t.id.indexOf('tknx') != -1 && + t.isRisk && + !t.isUserToken ), balances, visible @@ -525,6 +541,13 @@ export default function SelectToken({ } }, [tknTokensData?.length, loadingTKNTokensData, currentSort]); + useEffect(() => { + if (tknTokensData?.length && !loadingTKNXTokensData) { + tknxTokensData.sort(sortTypes[currentSort].fn); + setListTknxData(tknxTokensData); + } + }, [tknxTokensData?.length, loadingTKNXTokensData, currentSort]); + useEffect(() => { getLatestCommonBassesTokens(); }, [tokensData]); @@ -683,6 +706,10 @@ export default function SelectToken({
Created by any user on https://tkn.homes with the tkn.near suffix, poses high risks. Ref has not certified it. Exercise caution.
`; + const TknxTip = ` +
+ Created by any user on https://tkn.homes with the tknx.near suffix, poses high risks. Ref has not certified it. Exercise caution. +
`; return ( + {/* tknx */} + {/*
setActiveTab('TKNX')} + > + TKNX +
+ + +
+
*/}
{activeTab === 'Default' && ( @@ -915,6 +963,33 @@ export default function SelectToken({ showRiskTokens={true} /> )} + + {activeTab === 'TKNX' && ( + { + if (token.id != NEARXIDS[0]) { + if ( + !( + token.id == WRAP_NEAR_CONTRACT_ID && + token.symbol == 'wNEAR' && + !allowWNEAR + ) + ) { + onSelect && onSelect(token); + } + } + handleClose(); + }} + balances={balances} + forCross={forCross} + showRiskTokens={true} + /> + )}
@@ -950,6 +1025,13 @@ export default function SelectToken({ ) : null} + {tknSearchNoData && activeTab === 'TKNX' ? ( +
+
+ +
+
+ ) : null} )}
diff --git a/src/components/swap/SwapCard.tsx b/src/components/swap/SwapCard.tsx index 5ec27a0b9..87002ad19 100644 --- a/src/components/swap/SwapCard.tsx +++ b/src/components/swap/SwapCard.tsx @@ -12,7 +12,7 @@ import React, { import { FormattedMessage, useIntl } from 'react-intl'; import { useHistory, useLocation } from 'react-router-dom'; -import { CountdownTimer } from '../../components/icon'; +import { DEFLATION_MARK } from '../../utils/token'; import { RateExchangeMobile } from '../../components/icon/Common'; import { useWalletSelector } from '../../context/WalletSelectorContext'; import { TextWrapper } from '../../pages/Orderly/components/UserBoard'; @@ -28,6 +28,7 @@ import { ftGetBalance, REF_META_DATA, TokenMetadata, + tokenFtMetadata, } from '../../services/ft-contract'; import { USD_CLASS_STABLE_TOKEN_IDS } from '../../services/near'; import { @@ -731,6 +732,8 @@ export default function SwapCard(props: { const [balanceInDone, setBalanceInDone] = useState(false); const [balanceOutDone, setBalanceOutDone] = useState(false); + const [tokenDeflationRateData, setTokenDeflationRateData] = + useState>(); const intl = useIntl(); const location = useLocation(); @@ -910,7 +913,33 @@ export default function SwapCard(props: { setWrapOperation(false); } }, [tokenIn, tokenOut, useNearBalance, isSignedIn, nearBalance]); - + useEffect(() => { + if (tokenIn?.id) { + if (tokenIn?.id.includes(DEFLATION_MARK)) { + getTokenDeflationRate(); + } else { + setTokenDeflationRateData({ + rate: '0', + done: true, + }); + } + } else { + setTokenDeflationRateData(undefined); + } + }, [tokenIn?.id]); + async function getTokenDeflationRate() { + setTokenDeflationRateData(undefined); + const tokenMeta = await tokenFtMetadata(tokenIn.id); + const rate = + ((tokenMeta?.deflation_strategy?.fee_strategy?.SellFee?.fee_rate ?? 0) + + (tokenMeta?.deflation_strategy?.burn_strategy?.SellBurn?.burn_rate ?? + 0)) / + 1000000; + setTokenDeflationRateData({ + rate, + done: true, + }); + } function getStorageTokenId() { const in_key = localStorage.getItem(SWAP_IN_KEY); const in_key_symbol = localStorage.getItem(SWAP_IN_KEY_SYMBOL); @@ -959,10 +988,11 @@ export default function SwapCard(props: { useSwapPopUp(); useCrossSwapPopUp(); - useRefSwapPro({ tokenIn, - tokenInAmount, + tokenInAmount: Big(1 - (tokenDeflationRateData?.rate || 0)) + .mul(tokenInAmount || 0) + .toFixed(), tokenOut, slippageTolerance, setLoadingData, @@ -977,6 +1007,7 @@ export default function SwapCard(props: { setQuoting, setReEstimateTrigger, quoting, + tokenDeflationRateData, }); useEffect(() => { diff --git a/src/pages/SwapPage.tsx b/src/pages/SwapPage.tsx index 639b7df90..6bc777951 100644 --- a/src/pages/SwapPage.tsx +++ b/src/pages/SwapPage.tsx @@ -211,7 +211,6 @@ function getAllTokens(refTokens: TokenMetadata[], triTokens: TokenMetadata[]) { refTokens.push(tk); } }); - return refTokens; } @@ -341,7 +340,6 @@ function SwapPage() { const crossSwapTokens = allTokens.filter( (token) => token.onTri || token.onRef ); - const SwapNav = ( { return { ...nearMetadata, id: keepId ? token.id : nearMetadata.id }; else return token; }; + +export const tokenFtMetadata = async (tokenId: string) => { + const metadata = await ftViewFunction(tokenId, { + methodName: 'tknx_metadata', + }); + return metadata; +}; diff --git a/src/services/pool.ts b/src/services/pool.ts index 61ea7ca50..8a853e363 100644 --- a/src/services/pool.ts +++ b/src/services/pool.ts @@ -1,3 +1,4 @@ +import Big from 'big.js'; import { executeMultipleTransactions, LP_STORAGE_AMOUNT, @@ -13,6 +14,7 @@ import { ftGetStorageBalance, TokenMetadata, native_usdc_has_upgrated, + tokenFtMetadata, } from './ft-contract'; import { toNonDivisibleNumber, @@ -57,6 +59,7 @@ import { getStablePoolDecimal } from '../pages/stable/StableSwapEntry'; import { cacheAllDCLPools } from './swapV3'; import { REF_DCL_POOL_CACHE_KEY } from '../state/swap'; import getConfigV2 from '../services/configV2'; +import { DEFLATION_MARK } from '../utils/token'; const { NO_REQUIRED_REGISTRATION_TOKEN_IDS } = getConfigV2(); const explorerType = getExplorer(); @@ -774,9 +777,7 @@ export const addLiquidityToPool = async ({ id, tokenAmounts, }: AddLiquidityToPoolOptions) => { - // const transactions:Transaction[] = [] - - const amounts = tokenAmounts.map(({ token, amount }) => + let amounts = tokenAmounts.map(({ token, amount }) => toNonDivisibleNumber(token.decimals, amount) ); @@ -784,7 +785,35 @@ export const addLiquidityToPool = async ({ tokens: tokenAmounts.map(({ token, amount }) => token), amounts: tokenAmounts.map(({ token, amount }) => amount), }); - + // add deflation calc logic + const tknx_tokens = tokenAmounts + .map((item) => item.token) + .filter((token) => token.id.includes(DEFLATION_MARK)); + if (tknx_tokens.length > 0) { + const pending = tknx_tokens.map((token) => tokenFtMetadata(token.id)); + const tokenFtMetadatas = await Promise.all(pending); + const rate = tokenFtMetadatas.reduce((acc, cur, index) => { + const is_owner = + cur.owner_account_id == getCurrentWallet()?.wallet?.getAccountId(); + return { + ...acc, + [tknx_tokens[index].id]: is_owner + ? 0 + : (cur?.deflation_strategy?.fee_strategy?.SellFee?.fee_rate ?? 0) + + (cur?.deflation_strategy?.burn_strategy?.SellBurn?.burn_rate ?? 0), + }; + }, {}); + amounts = tokenAmounts.map(({ token, amount }) => { + const reforeAmount = toNonDivisibleNumber(token.decimals, amount); + let afterAmount = reforeAmount; + if (rate[token.id]) { + afterAmount = Big(1 - rate[token.id] / 1000000) + .mul(reforeAmount) + .toFixed(0); + } + return afterAmount; + }); + } const actions: RefFiFunctionCallOptions[] = [ { methodName: 'add_liquidity', diff --git a/src/state/swap.tsx b/src/state/swap.tsx index 3bda309ba..a270a97a6 100644 --- a/src/state/swap.tsx +++ b/src/state/swap.tsx @@ -97,6 +97,7 @@ interface SwapOptions { setRequestingTrigger?: (requestingTrigger?: boolean) => void; wrapOperation?: boolean; reEstimatingPro?: boolean; + tokenDeflationRateData?: Record; } interface SwapV3Options { @@ -397,6 +398,7 @@ export const useSwap = ({ loadingPause, reEstimateTrigger, supportLedger, + tokenDeflationRateData, }: SwapOptions) => { const [pool, setPool] = useState(); const [canSwap, setCanSwap] = useState(); @@ -469,8 +471,8 @@ export const useSwap = ({ return; } - setEstimating(true); + setEstimating(true); estimateSwap({ tokenIn, tokenOut, @@ -581,7 +583,7 @@ export const useSwap = ({ ), tokenOut ); - + if (!tokenDeflationRateData) return; if (estimating && swapsToDo && !forceEstimate) return; if (valRes && !loadingTrigger && !forceEstimate) { @@ -598,6 +600,7 @@ export const useSwap = ({ reEstimateTrigger, enableTri, forceEstimate, + tokenDeflationRateData?.rate, ]); useEffect(() => { @@ -616,12 +619,12 @@ export const useSwap = ({ ), tokenOut ); - + if (!tokenDeflationRateData) return; if (estimating && swapsToDo && !forceEstimate) return; if (((valRes && !loadingTrigger) || swapError) && !forceEstimate) return; getEstimate(); - }, [estimating]); + }, [estimating, tokenDeflationRateData?.rate]); useEffect(() => { setForceEstimate(true); @@ -653,7 +656,9 @@ export const useSwap = ({ slippageTolerance, swapsToDo, tokenIn, - amountIn: tokenInAmount, + amountIn: Big(tokenInAmount) + .div(Big(1).minus(tokenDeflationRateData?.rate || 0)) + .toFixed(), tokenOut, swapMarket: 'ref', }).catch(setSwapError); @@ -1495,10 +1500,10 @@ export const useRefSwap = ({ reEstimateTrigger, supportLedger, loadingData, + tokenDeflationRateData, }: SwapOptions): ExchangeEstimate => { const { canSwap, - // tokenOutAmount, minAmountOut, swapError, makeSwap: makeSwapV1, @@ -1522,6 +1527,7 @@ export const useRefSwap = ({ swapMode, reEstimateTrigger, supportLedger, + tokenDeflationRateData, }); const [estimateInAmount, tokenOutAmount] = estimateInOut; @@ -1927,6 +1933,7 @@ export const useRefSwapPro = ({ setReEstimateTrigger, setQuoting, quoting, + tokenDeflationRateData, }: SwapOptions & { setQuoting: (quoting: boolean) => void; quoting: boolean; @@ -1940,7 +1947,6 @@ export const useRefSwapPro = ({ selectMarket, swapType, } = useContext(SwapProContext); - const resRef = useRefSwap({ tokenIn, tokenInAmount, @@ -1954,6 +1960,7 @@ export const useRefSwapPro = ({ reEstimateTrigger, supportLedger, loadingData, + tokenDeflationRateData, }); resRef.hasTriPool = @@ -2004,9 +2011,6 @@ export const useRefSwapPro = ({ }; const tradeList = [resRef, resAurora]; - - // reValidate trades - let resValid = true; resValid = @@ -2042,7 +2046,6 @@ export const useRefSwapPro = ({ setReEstimateTrigger(!reEstimateTrigger); return; } - setTrades(trades); const bestMarket = Object.keys(trades).reduce((a, b) => { diff --git a/src/state/token.ts b/src/state/token.ts index e354e6a82..cee922879 100644 --- a/src/state/token.ts +++ b/src/state/token.ts @@ -171,6 +171,9 @@ export const useWhitelistTokens = (extraTokenIds: string[] = []) => { ]; const allTokens = await getAllTokens(); const postfix = await get_auto_whitelisted_postfix(); + // for tknx + postfix.push('.tknx'); + postfix.push('.tkns'); const whiteMetaDataList = await Promise.all( allWhiteTokenIds.map((tokenId) => ftGetTokenMetadata(tokenId)) ); @@ -335,7 +338,7 @@ export const useWalletTokenBalances = (tokenIds: string[] = []) => { if (tokenIds.some((id) => !id)) return; Promise.all(tokenIds.map((id) => ftGetBalance(id))).then((res) => { - let balances = {}; + const balances = {}; res.map((item, index) => { const tokenId: string = tokenIds[index]; balances[tokenId] = item; diff --git a/src/utils/token.ts b/src/utils/token.ts index b7b42b0ea..88217a3d7 100644 --- a/src/utils/token.ts +++ b/src/utils/token.ts @@ -15,3 +15,4 @@ export const toRealSymbol = (symbol: string) => { export const getMftTokenId = (id: string) => { return ':' + id; }; +export const DEFLATION_MARK = 'tknx.near';