Skip to content

Commit

Permalink
Updated jup token fetch to directly load unverified tokens (#2403)
Browse files Browse the repository at this point in the history
  • Loading branch information
ritrafa authored Sep 24, 2024
1 parent b539996 commit ceea061
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 2 deletions.
4 changes: 2 additions & 2 deletions hooks/useTreasuryInfo/convertAccountToAsset.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BigNumber } from 'bignumber.js'

import { AccountType, AssetAccount } from '@utils/uiTypes/assets'
import { AssetType, Asset } from '@models/treasury/Asset'
import { getTreasuryAccountItemInfoV2 } from '@utils/treasuryTools'
import { getTreasuryAccountItemInfoV2Async } from '@utils/treasuryTools'
import TokenIcon from '@components/treasuryV2/icons/TokenIcon'
import { WSOL_MINT } from '@components/instructions/tools'
import { abbreviateAddress } from '@utils/formatting'
Expand All @@ -16,7 +16,7 @@ export const convertAccountToAsset = async (
councilMintAddress?: string,
communityMintAddress?: string
): Promise<Asset | null> => {
const info = getTreasuryAccountItemInfoV2(account)
const info = await getTreasuryAccountItemInfoV2Async(account)

switch (account.type) {
case AccountType.AUXILIARY_TOKEN:
Expand Down
47 changes: 47 additions & 0 deletions utils/services/tokenPrice.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { USDC_MINT } from '@blockworks-foundation/mango-v4'
//decimals from metadata can be different from the realm on chain one
const priceEndpoint = 'https://price.jup.ag/v4/price'
const tokenListUrl = 'https://token.jup.ag/strict'
//const tokenListUrl = 'https://tokens.jup.ag/tokens' // The full list is available but takes much longer to load

export type TokenInfoWithoutDecimals = Omit<TokenInfo, 'decimals'>

Expand All @@ -21,9 +22,11 @@ class TokenPriceService {
_tokenPriceToUSDlist: {
[mintAddress: string]: Price
}
_unverifiedTokenCache: { [mintAddress: string]: TokenInfoWithoutDecimals };
constructor() {
this._tokenList = []
this._tokenPriceToUSDlist = {}
this._unverifiedTokenCache = {}
}
async fetchSolanaTokenList() {
try {
Expand Down Expand Up @@ -114,6 +117,50 @@ class TokenPriceService {
)
return tokenListRecord
}

// This async method is used to lookup additional tokens not on JUP's strict list
async getTokenInfoAsync(mintAddress: string): Promise<TokenInfoWithoutDecimals | undefined> {
if (!mintAddress || mintAddress.trim() === '') {
return undefined;
}
// Check the strict token list first
let tokenListRecord = this._tokenList?.find((x) => x.address === mintAddress);
if (tokenListRecord) {
return tokenListRecord;
}

// Check the unverified token list cache next to avoid repeatedly loading token metadata
if (this._unverifiedTokenCache[mintAddress]) {
return this._unverifiedTokenCache[mintAddress];
}

// Get the token data from JUP's api
const requestURL = `https://tokens.jup.ag/token/${mintAddress}`
const response = await axios.get(requestURL);

if (response.data) {
// Remove decimals and add chainId to match the TokenInfoWithoutDecimals struct
const { decimals, ...tokenInfoWithoutDecimals } = response.data;
const finalTokenInfo = {
...tokenInfoWithoutDecimals,
chainId: 101
};

// Add to unverified token cache
this._unverifiedTokenCache[mintAddress] = finalTokenInfo;

return finalTokenInfo;
} else {
console.error(`Metadata retrieving failed for ${mintAddress}`);
return undefined;
}
} catch (e) {
notify({
type: 'error',
message: 'Unable to fetch token information',
});
return undefined;
}
/**
* For decimals use on chain tryGetMint
*/
Expand Down
64 changes: 64 additions & 0 deletions utils/treasuryTools.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,67 @@ export const getTreasuryAccountItemInfoV2 = (account: AssetAccount) => {
totalPrice,
}
}

//This async method added to add a lookup for token metadata not available in JUP's strict list
export const getTreasuryAccountItemInfoV2Async = async (account: AssetAccount) => {
const mintAddress =
account.type === AccountType.SOL
? WSOL_MINT
: account.extensions.mint?.publicKey.toBase58()

const amount =
account.extensions.amount && account.extensions.mint
? getMintDecimalAmountFromNatural(
account.extensions.mint.account,
new BN(
account.isSol
? account.extensions.solAccount!.lamports
: account.extensions.amount
)
).toNumber()
: 0
const price = tokenPriceService.getUSDTokenPrice(mintAddress!)
const totalPrice = amount * price
const totalPriceFormatted = amount
? new BigNumber(totalPrice).toFormat(0)
: ''
const info = await tokenPriceService.getTokenInfoAsync(mintAddress!)

const symbol =
account.type === AccountType.NFT
? 'NFTS'
: account.type === AccountType.SOL
? 'SOL'
: info?.symbol
? info.address === WSOL_MINT
? 'wSOL'
: info?.symbol
: account.extensions.mint
? abbreviateAddress(account.extensions.mint.publicKey)
: ''
const amountFormatted = new BigNumber(amount).toFormat()

const logo = info?.logoURI || ''
const accountName = account.pubkey ? getAccountName(account.pubkey) : ''
const name = accountName
? accountName
: account.extensions.transferAddress
? abbreviateAddress(account.extensions.transferAddress as PublicKey)
: ''

const displayPrice =
totalPriceFormatted && totalPriceFormatted !== '0'
? totalPriceFormatted
: ''

return {
accountName,
amountFormatted,
logo,
name,
displayPrice,
info,
symbol,
totalPrice,
}
}

0 comments on commit ceea061

Please sign in to comment.