asset-tracker
Version:
Asset tracker to track all your multichain assets.
215 lines (152 loc) • 6.41 kB
JavaScript
const Web3 = require('web3');
const validator = require('../utils/input-validator');
const helper = require('../utils/helper');
const chains = require('../chains');
const responses = require('../constants/responses');
const erc20ABI = require('../constants/erc20-abi');
const erc721ABI = require('../constants/erc721-abi');
class EVM {
constructor(chainName) {
validator.validateConstructor('EVM', chainName);
this.chain = chainName;
this.web3 = new Web3(new Web3.providers.HttpProvider(chains[chainName].RPC));
}
switchChain(chainName) {
validator.validateConstructor('EVM', chainName);
this.chain = chainName;
this.web3 = new Web3(new Web3.providers.HttpProvider(chains[chainName].RPC));
}
async getNativeAssetBalance(address) {
validator.validateAddress(address);
const checksumAddress = this.web3.utils.toChecksumAddress(address);
const balance = await this.web3.eth.getBalance(checksumAddress);
return this.web3.utils.fromWei(balance.toString(), 'ether');
}
async getNativeAssetDetails() {
validator.checkSupportForChains(this.chain, 'getNativeAssetDetails');
const details = await helper.getRequest(`${chains[this.chain].ASSET_API}`);
let response = {};
response.chain = details.name;
response.symbol = details.symbol;
response.image = details.image.large;
response.currentPrice = details.market_data.current_price.usd;
response.marketCap = details.market_data.market_cap.usd;
response.high_24h = details.market_data.high_24h.usd;
response.low_24h = details.market_data.low_24h.usd;
return response;
}
async discoverFungibleAssets(address) {
validator.checkSupportForChains(this.chain, 'discoverFungibleAssets');
validator.validateAddress(address);
const checksumAddress = this.web3.utils.toChecksumAddress(address);
const assets = await helper.getRequest(chains[this.chain].EVM_FUNGIBLE_ASSET_DISCOVERY_API(checksumAddress, chains[this.chain].CHAIN_ID));
const assetDetails = [];
assets.tokenBalances.forEach((asset) => {
const obj = {};
obj.name = asset.name;
obj.symbol = asset.symbol;
obj.balance = asset.balance;
obj.decimals = asset.decimals;
obj.priceInUSD = asset.value.price;
obj.iconURL = asset.iconUrl;
assetDetails.push(obj);
});
return assetDetails;
}
async discoverNonFungibleAssets(address) {
validator.checkSupportForChains(this.chain, 'discoverNonFungibleAssets');
validator.validateAddress(address);
const checksumAddress = this.web3.utils.toChecksumAddress(address);
const assets = await helper.getRequest(chains[this.chain].EVM_NON_FUNGIBLE_ASSET_DISCOVERY_API(checksumAddress));
const assetDetails = [];
const filteredData = assets.data.filter((asset) => asset.chainId === chains[this.chain].CHAIN_ID);
filteredData.forEach((asset) => {
const obj = {};
obj.name = asset.name;
obj.symbol = asset.symbol;
obj.tokenId = asset.tokenId;
obj.tokenUrl = asset.tokenUrl;
obj.contractAddress = asset.tokenAddress;
obj.metadata = { name: asset.metadata.name };
obj.metadata.description = asset.metadata.description;
obj.metadata.image = asset.metadata.image;
assetDetails.push(obj);
});
return assetDetails;
}
async getTransactions({
address, page, limit, type = 'all',
}) {
validator.checkSupportForChains(this.chain, 'getTransactions');
validator.validateAddress(address);
if (type !== 'incoming' && type !== 'outgoing' && type !== 'all') {
throw responses.INVALID_TYPE_PASSED;
}
const checksumAddress = this.web3.utils.toChecksumAddress(address);
const apiURL = chains[this.chain].GET_TXN_LIST_API(checksumAddress, page, limit);
const transactions = await helper.getRequest(apiURL);
let txDetails = [];
transactions.result.forEach((txn) => {
const obj = { };
obj.from = txn.from;
obj.to = txn.to || txn.contractAddress;
obj.blockNumber = txn.blockNumber;
obj.transactionHash = txn.hash;
obj.nonce = txn.nonce;
obj.value = txn.value;
obj.gas = txn.gas;
obj.gasPrice = txn.gasPrice;
obj.transactionSuccess = txn.isError === '0';
obj.input = txn.input;
obj.methodId = txn.methodId;
obj.function = txn.functionName;
txDetails.push(obj);
});
if (type === 'incoming') {
txDetails = txDetails.filter((element) => element.to === address);
} else if (type === 'outgoing') {
txDetails = txDetails.filter((element) => element.from === address);
}
return txDetails;
}
async getFungibleTokenDetails(contractAddress) {
validator.validateAddress(contractAddress);
const checksumAddress = this.web3.utils.toChecksumAddress(contractAddress);
await validator.validateContractAddress(this.web3, checksumAddress);
const erc20Instance = new this.web3.eth.Contract(erc20ABI, checksumAddress);
const totalSupply = await erc20Instance.methods.totalSupply().call();
const name = await erc20Instance.methods.name().call();
const symbol = await erc20Instance.methods.symbol().call();
const decimals = await erc20Instance.methods.decimals().call();
return {
totalSupply, name, symbol, decimals,
};
}
async getNFTDetails(contractAddress) {
validator.validateAddress(contractAddress);
const checksumAddress = this.web3.utils.toChecksumAddress(contractAddress);
await validator.validateContractAddress(this.web3, checksumAddress);
const erc721Instance = new this.web3.eth.Contract(erc721ABI, checksumAddress);
const name = await erc721Instance.methods.name().call();
const symbol = await erc721Instance.methods.symbol().call();
return {
name, symbol,
};
}
getSupportedChains(functionName = 'all') {
validator.validateFunctionName(functionName);
const chainsArray = [];
if (functionName === 'all') {
chainsArray.push(...Object.keys(chains.evmChains));
} else {
const chainsArr = Object.keys(chains.evmChains);
for (let i = 0; i < chainsArr.length; i += 1) {
if (chains[chainsArr[i]].FUNCTIONALITY_SUPPORT[functionName]) {
chainsArray.push(chains[chainsArr[i]].NAME.toLowerCase());
}
}
}
return chainsArray;
}
}
module.exports = EVM;