import { Tx } from '@d11k-ts/client' import { bnOrZero } from '@d11k-ts/utils' import axios from 'axios' import { BigNumberish } from 'ethers' import { ETHTransactionInfo, GasOracleResponse, TokenBalanceParam, TokenTransactionInfo, TransactionHistoryParam, } from './types' import { filterSelfTxs, getTxFromEthTransaction, getTxFromTokenTransaction } from './utils' const getApiKeyQueryParameter = (apiKey?: string): string => (!!apiKey ? `&apiKey=${apiKey}` : '') /** * SafeGasPrice, ProposeGasPrice And FastGasPrice returned in string-Gwei * * @see https://etherscan.io/apis#gastracker * * @param {string} baseUrl The etherscan node url. * @param {string} apiKey The etherscan API key. (optional) * @returns {GasOracleResponse} LastBlock, SafeGasPrice, ProposeGasPrice, FastGasPrice */ export const getGasOracle = async (baseUrl: string, apiKey?: string): Promise => { const url = baseUrl + '/api?module=gastracker&action=gasoracle' return (await axios.get(url + getApiKeyQueryParameter(apiKey))).data.result } /** * Get token balance * * @see https://etherscan.io/apis#tokens * * @param {string} baseUrl The etherscan node url. * @param {string} address The address. * @param {string} assetAddress The token contract address. * @param {string} apiKey The etherscan API key. (optional) * @returns {BigNumberish} The token balance */ export const getTokenBalance = async ({ baseUrl, address, assetAddress, apiKey, }: TokenBalanceParam & { baseUrl: string; apiKey?: string }): Promise => { const url = baseUrl + `/api?module=account&action=tokenbalance&contractaddress=${assetAddress}&address=${address}` return (await axios.get(url + getApiKeyQueryParameter(apiKey))).data.result } /** * Get ETH transaction history * * @see https://etherscan.io/apis#accounts * * @param {string} baseUrl The etherscan node url. * @param {string} address The address. * @param {TransactionHistoryParam} params The search options. * @param {string} apiKey The etherscan API key. (optional) * @returns {ETHTransactionInfo[]} The ETH transaction history */ export const getETHTransactionHistory = async ({ baseUrl, address, page, offset, startblock, endblock, apiKey, }: TransactionHistoryParam & { baseUrl: string; apiKey?: string }): Promise => { let url = baseUrl + `/api?module=account&action=txlist&sort=desc` + getApiKeyQueryParameter(apiKey) if (address) url += `&address=${address}` if (offset) url += `&offset=${offset}` if (page) url += `&page=${page}` if (startblock) url += `&startblock=${startblock}` if (endblock) url += `&endblock=${endblock}` const result = (await axios.get(url)).data.result if (JSON.stringify(result).includes('Invalid API Key')) throw new Error('Invalid API Key') if (typeof result !== 'object') throw new Error(result) return filterSelfTxs(result) .filter((tx) => !bnOrZero(tx.value).isZero()) .map(getTxFromEthTransaction) } /** * Get token transaction history * * @see https://etherscan.io/apis#accounts * * @param {string} baseUrl The etherscan node url. * @param {string} address The address. * @param {TransactionHistoryParam} params The search options. * @param {string} apiKey The etherscan API key. (optional) * @returns {Tx[]} The token transaction history */ export const getTokenTransactionHistory = async ({ baseUrl, address, assetAddress, page, offset, startblock, endblock, apiKey, }: TransactionHistoryParam & { baseUrl: string; apiKey?: string }): Promise => { let url = baseUrl + `/api?module=account&action=tokentx&sort=desc` + getApiKeyQueryParameter(apiKey) if (address) url += `&address=${address}` if (assetAddress) url += `&contractaddress=${assetAddress}` if (offset) url += `&offset=${offset}` if (page) url += `&page=${page}` if (startblock) url += `&startblock=${startblock}` if (endblock) url += `&endblock=${endblock}` const result = (await axios.get(url)).data.result if (JSON.stringify(result).includes('Invalid API Key')) throw new Error('Invalid API Key') return filterSelfTxs(result) .filter((tx) => !bnOrZero(tx.value).isZero()) .reduce((acc, cur) => { const tx = getTxFromTokenTransaction(cur) return tx ? [...acc, tx] : acc }, [] as Tx[]) }