zerion-sdk
Version:
A Typed Interface for ZerionAPI
168 lines (167 loc) • 6.46 kB
JavaScript
// Transform position data to user dashboard response
export function transformPositionDataToUserDashboardResponse(positions,
// This part is only used for chain icons (it is basically static input)
chains, options, isTestnet) {
// Create a map of chains for O(1) access
const chainMap = new Map();
chains.forEach((chain) => {
const numberId = parseInt(chain.attributes.external_id, 16);
// Only add chains that are supported (if filter is provided)
if (!options?.supportedChains?.length ||
options.supportedChains.includes(numberId)) {
chainMap.set(chain.id, {
name: chain.attributes.name,
icon: chain.attributes.icon.url,
numberId,
zerionId: chain.id,
});
}
});
let totalUsdBalance = 0;
const chainSet = new Set();
const chainsIcons = {};
// Track which chains have positions
const chainsWithPositions = new Set();
const tokens = positions
.map((position) => {
const { attributes, relationships } = position;
// Extract chain info
const chain = chainMap.get(relationships.chain.data.id);
// Skip if chain is not supported
if (!chain) {
return null;
}
chainsWithPositions.add(chain.zerionId);
chainsIcons[chain.numberId] = chain.icon;
chainSet.add(chain.name);
// Update total USD balance
totalUsdBalance += attributes.value || 0;
// Get chain icon from zerion.getChains.
const chainIcon = chain.icon;
const contractAddress = findImplementation(chain, attributes.fungible_info.implementations)?.address;
const tokenIcon = attributes.fungible_info.icon?.url;
// Extract balances and token metadata
const userToken = {
chain: {
chainId: chain.numberId,
chainName: chain.name,
...(chainIcon ? { chainIcon } : {}),
},
balances: {
balance: Number(attributes.quantity.numeric),
// Testnet tokens are valueless we assign a fake value of 1.
usdBalance: isTestnet
? attributes.quantity.float
: attributes.value || 0,
price: isTestnet ? 1 : (attributes.price ?? 0),
},
meta: {
name: attributes.fungible_info.name,
symbol: attributes.fungible_info.symbol,
decimals: attributes.quantity.decimals,
isSpam: attributes.flags.is_trash,
...(tokenIcon ? { tokenIcon } : {}),
...(contractAddress ? { contractAddress } : {}),
},
};
// Exclude anything with value less than hideDust
if (options?.hideDust &&
userToken.balances.usdBalance < options.hideDust) {
return null;
}
return userToken;
})
.filter((token) => token !== null);
// Add zero balances for native tokens where needed
if (options?.showZeroNative && options.nativeTokens) {
for (const [chainId, nativeToken] of Object.entries(options.nativeTokens)) {
const chain = chainMap.get(chainId);
if (!chain || chainsWithPositions.has(chainId))
continue;
chainsIcons[chain.numberId] = chain.icon;
chainSet.add(chain.name);
tokens.push({
chain: {
chainId: chain.numberId,
chainName: chain.name,
...(chain.icon ? { chainIcon: chain.icon } : {}),
},
balances: {
balance: 0,
usdBalance: 0,
price: nativeToken.attributes.market_data?.price || 0,
},
meta: {
name: nativeToken.attributes.name,
symbol: nativeToken.attributes.symbol,
decimals: findImplementation(chain, nativeToken.attributes.implementations)
?.decimals || 18,
isSpam: false,
tokenIcon: nativeToken.attributes.icon?.url,
},
});
}
}
return {
tokens,
totalUsdBalance,
chains: Array.from(chainSet),
chainsIcons,
};
}
// Transform NFT data to user NFTs response
export function transformNftDataToUserNftResponse(positions,
// This part is only used for chain icons (it is basically static input)
chains, options) {
const chainsMap = (() => {
const m = new Map();
chains.forEach((c) => {
const numericId = parseInt(c.attributes.external_id, 16);
if (!options?.supportedChains?.length ||
options.supportedChains.includes(numericId))
m.set(c.id, {
name: c.attributes.name,
icon: c.attributes.icon.url,
numericId,
});
});
return m;
})();
const chainsSet = new Set();
const chainsIcons = {};
const nfts = positions.map((nft) => {
const { detail, preview, video } = nft.attributes.nft_info.content;
const media = detail?.url || preview?.url || video?.url || null;
const chain = chainsMap.get(nft.relationships.chain.data.id);
chainsSet.add(chain.name);
chainsIcons[chain.numericId] = chain.icon;
return {
nft_contract_id: nft.attributes.nft_info.contract_address,
token_id: nft.attributes.nft_info.token_id,
minter: null,
owner: null,
base_uri: null,
metadata_id: null,
title: nft.attributes.nft_info.name,
description: null,
media,
reference: null,
reference_blob: null,
minted_timestamp: null,
last_transfer_timestamp: null,
price: nft.attributes.price?.toString() || null,
currency: null,
chain: chain.name,
chain_id: chain.numericId,
};
});
return {
nfts,
totalNfts: nfts.length,
chains: Array.from(chainsSet),
chainsIcons,
};
}
function findImplementation(chain, implementations) {
return implementations.find((impl) => impl.chain_id === chain.zerionId);
}