Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@xchainjs/xchain-evm

Package Overview
Dependencies
Maintainers
10
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@xchainjs/xchain-evm - npm Package Compare versions

Comparing version 0.2.2 to 0.3.0

5

lib/client.d.ts

@@ -22,3 +22,3 @@ import { Provider, TransactionResponse } from '@ethersproject/abstract-provider';

explorerProviders: ExplorerProviders;
dataProviders: OnlineDataProviders;
dataProviders: OnlineDataProviders[];
};

@@ -275,3 +275,6 @@ /**

getFees(params: TxParams): Promise<Fees>;
protected roundRobinGetBalance(address: Address, assets?: Asset[]): Promise<Balance[]>;
protected roundRobinGetTransactionData(txId: string, assetAddress?: string): Promise<Tx>;
protected roundRobinGetTransactions(params: TxHistoryParams): Promise<TxsPage>;
}
export { Client };

1

lib/index.d.ts
export * from './types';
export * from './client';
export * from './providers';
export { call, estimateApprove, estimateCall, getApprovalAmount, getTokenAddress, getPrefix, isApproved, strip0x, validateAddress, MAX_APPROVAL, } from './utils';

@@ -5,0 +4,0 @@ export declare const abi: {

@@ -1,6 +0,5 @@

import { BaseXChainClient, Network, FeeOption, checkFeeBounds, standardFeeRates, FeeType, TxType } from '@xchainjs/xchain-client';
import { baseAmount, eqAsset, assetToString, bnOrZero, assetFromString } from '@xchainjs/xchain-util';
import { BaseXChainClient, Network, FeeOption, checkFeeBounds, standardFeeRates, FeeType } from '@xchainjs/xchain-client';
import { baseAmount, eqAsset, assetToString } from '@xchainjs/xchain-util';
import { ethers, Wallet, BigNumber } from 'ethers';
import { HDNode, toUtf8Bytes } from 'ethers/lib/utils';
import axios from 'axios';

@@ -32,3 +31,3 @@ /******************************************************************************

var erc20ABI$1 = [
var erc20ABI = [
{

@@ -275,3 +274,3 @@ inputs: [

*/
const validateAddress$1 = (address) => {
const validateAddress = (address) => {
try {

@@ -389,3 +388,3 @@ ethers.utils.getAddress(address);

const txAmount = ethers.BigNumber.from((_a = amount === null || amount === void 0 ? void 0 : amount.amount().toFixed()) !== null && _a !== void 0 ? _a : 1);
const contract = new ethers.Contract(contractAddress, erc20ABI$1, provider);
const contract = new ethers.Contract(contractAddress, erc20ABI, provider);
const allowance = yield contract.allowance(fromAddress, spenderAddress);

@@ -551,3 +550,3 @@ return txAmount.lte(allowance);

validateAddress(address) {
return validateAddress$1(address);
return validateAddress(address);
}

@@ -564,6 +563,3 @@ /**

return __awaiter(this, void 0, void 0, function* () {
const prov = this.dataProviders[this.network];
if (!prov)
throw Error('Provider unidefined');
return yield prov.getBalance(address, assets);
return yield this.roundRobinGetBalance(address, assets);
});

@@ -587,6 +583,3 @@ }

};
const prov = this.dataProviders[this.network];
if (!prov)
throw Error('Provider unidefined');
return yield prov.getTransactions(filteredParams);
return yield this.roundRobinGetTransactions(filteredParams);
});

@@ -606,6 +599,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const prov = this.dataProviders[this.network];
if (!prov)
throw Error('Provider unidefined');
return yield prov.getTransactionData(txId, assetAddress);
return yield this.roundRobinGetTransactionData(txId, assetAddress);
});

@@ -707,3 +697,3 @@ }

const valueToApprove = getApprovalAmount(amount);
const contract = new ethers.Contract(contractAddress, erc20ABI$1, this.getProvider());
const contract = new ethers.Contract(contractAddress, erc20ABI, this.getProvider());
/* as same as ethers.TransactionResponse expected by `sendTransaction` */

@@ -733,3 +723,3 @@ const unsignedTx = yield contract.populateTransaction.approve(spenderAddress, valueToApprove);

fromAddress,
abi: erc20ABI$1,
abi: erc20ABI,
amount,

@@ -800,3 +790,3 @@ });

contractAddress: assetAddress,
abi: erc20ABI$1,
abi: erc20ABI,
funcName: 'transfer',

@@ -877,3 +867,3 @@ funcParams: [recipient, txAmount, Object.assign({}, overrides)],

throw Error(`Can't get address from asset ${assetToString(theAsset)}`);
const contract = new ethers.Contract(assetAddress, erc20ABI$1, this.getProvider());
const contract = new ethers.Contract(assetAddress, erc20ABI, this.getProvider());
gasEstimate = yield contract.estimateGas.transfer(recipient, txAmount, {

@@ -938,561 +928,45 @@ from: this.getAddress(),

}
}
var erc20ABI = [
{
inputs: [
],
stateMutability: "nonpayable",
type: "constructor"
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "owner",
type: "address"
},
{
indexed: true,
internalType: "address",
name: "spender",
type: "address"
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "Approval",
type: "event"
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "from",
type: "address"
},
{
indexed: true,
internalType: "address",
name: "to",
type: "address"
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "Transfer",
type: "event"
},
{
inputs: [
{
internalType: "address",
name: "",
type: "address"
},
{
internalType: "address",
name: "",
type: "address"
}
],
name: "allowance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address"
},
{
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "approve",
outputs: [
{
internalType: "bool",
name: "success",
type: "bool"
}
],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "",
type: "address"
}
],
name: "balanceOf",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "decimals",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "name",
outputs: [
{
internalType: "string",
name: "",
type: "string"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "symbol",
outputs: [
{
internalType: "string",
name: "",
type: "string"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "to",
type: "address"
},
{
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "transfer",
outputs: [
{
internalType: "bool",
name: "success",
type: "bool"
}
],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address"
},
{
internalType: "address",
name: "to",
type: "address"
},
{
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "transferFrom",
outputs: [
{
internalType: "bool",
name: "success",
type: "bool"
}
],
stateMutability: "nonpayable",
type: "function"
}
];
ethers.BigNumber.from(2).pow(256).sub(1);
/**
* Validate the given address.
*
* @param {Address} address
* @returns {boolean} `true` or `false`
*/
const validateAddress = (address) => {
try {
ethers.utils.getAddress(address);
return true;
}
catch (error) {
return false;
}
};
const getApiKeyQueryParameter = (apiKey) => (!!apiKey ? `&apiKey=${apiKey}` : '');
/**
* Filter self txs
*
* @returns {T[]}
*
**/
const filterSelfTxs = (txs) => {
const filterTxs = txs.filter((tx) => tx.from !== tx.to);
let selfTxs = txs.filter((tx) => tx.from === tx.to);
while (selfTxs.length) {
const selfTx = selfTxs[0];
filterTxs.push(selfTx);
selfTxs = selfTxs.filter((tx) => tx.hash !== selfTx.hash);
}
return filterTxs;
};
/**
* Check if the symbol is valid.
*
* @param {string|null|undefined} symbol
* @returns {boolean} `true` or `false`.
*/
const validateSymbol = (symbol) => (symbol ? symbol.length >= 3 : false);
/**
* Get transactions from ETH transaction
*
* @param {ETHTransactionInfo} tx
* @returns {Tx} The parsed transaction.
*/
const getTxFromEthTransaction = (tx, gasAsset, decimals) => {
return {
asset: gasAsset,
from: [
{
from: tx.from,
amount: baseAmount(tx.value, decimals),
},
],
to: [
{
to: tx.to,
amount: baseAmount(tx.value, decimals),
},
],
date: new Date(parseInt(tx.timeStamp) * 1000),
type: TxType.Transfer,
hash: tx.hash,
};
};
/**
* Get transactions from token tx
*
* @param {TokenTransactionInfo} tx
* @returns {Tx|null} The parsed transaction.
*/
const getTxFromTokenTransaction = (tx, chain, decimals) => {
const decimal = parseInt(tx.tokenDecimal) || decimals;
const symbol = tx.tokenSymbol;
const address = tx.contractAddress;
if (validateSymbol(symbol) && validateAddress(address)) {
const tokenAsset = assetFromString(`${chain}.${symbol}-${address}`);
if (tokenAsset) {
return {
asset: tokenAsset,
from: [
{
from: tx.from,
amount: baseAmount(tx.value, decimal),
},
],
to: [
{
to: tx.to,
amount: baseAmount(tx.value, decimal),
},
],
date: new Date(parseInt(tx.timeStamp) * 1000),
type: TxType.Transfer,
hash: tx.hash,
};
}
}
return null;
};
/**
* 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
*/
const getGasAssetTransactionHistory = ({ gasAsset, gasDecimals, baseUrl, address, page, offset, startblock, endblock, apiKey, }) => __awaiter(void 0, void 0, void 0, function* () {
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 = (yield 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((tx) => getTxFromEthTransaction(tx, gasAsset, gasDecimals));
});
/**
* 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
*/
const getTokenTransactionHistory = ({ gasDecimals, baseUrl, address, assetAddress, page, offset, startblock, endblock, apiKey, chain, }) => __awaiter(void 0, void 0, void 0, function* () {
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 = (yield 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, chain, gasDecimals);
return tx ? [...acc, tx] : acc;
}, []);
});
class EtherscanProvider {
constructor(provider, baseUrl, apiKey, chain, nativeAsset, nativeAssetDecimals) {
this.provider = provider;
this.baseUrl = baseUrl;
this.apiKey = apiKey;
this.chain = chain;
this.nativeAsset = nativeAsset;
this.nativeAssetDecimals = nativeAssetDecimals;
this.nativeAsset;
this.chain;
}
getBalance(address, assets) {
roundRobinGetBalance(address, assets) {
return __awaiter(this, void 0, void 0, function* () {
//validate assets are for the correct chain
assets === null || assets === void 0 ? void 0 : assets.forEach((i) => {
if (i.chain !== this.chain)
throw Error(`${assetToString(i)} is not an asset of ${this.chain}`);
});
const balances = [];
if (assets) {
for (const asset of assets) {
if (asset.symbol === this.nativeAsset.symbol) {
balances.push(yield this.getNativeAssetBalance(address));
}
else {
const splitSymbol = asset.symbol.split('-');
const tokenSymbol = splitSymbol[0];
const contractAddress = splitSymbol[1];
balances.push(yield this.getTokenBalance(address, contractAddress, tokenSymbol));
}
for (const provider of this.dataProviders) {
try {
const prov = provider[this.network];
if (prov)
return yield prov.getBalance(address, assets);
}
}
else {
//get nativeAsset
balances.push(yield this.getNativeAssetBalance(address));
// Get All Erc-20 txs
const response = (yield axios.get(`${this.baseUrl}/api?module=account&action=tokentx&address=${address}&startblock=0&sort=asc&apikey=${this.apiKey}`)).data;
const erc20TokenTxs = this.getUniqueContractAddresses(response.result);
for (const erc20Token of erc20TokenTxs) {
balances.push(yield this.getTokenBalance(address, erc20Token.contractAddress, erc20Token.tokenSymbol));
catch (error) {
console.warn(error);
}
}
return balances;
throw Error('no provider able to get balance');
});
}
getNativeAssetBalance(address) {
roundRobinGetTransactionData(txId, assetAddress) {
return __awaiter(this, void 0, void 0, function* () {
const gasAssetBalance = yield this.provider.getBalance(address);
const amount = baseAmount(gasAssetBalance.toString(), this.nativeAssetDecimals);
return {
asset: this.nativeAsset,
amount,
};
});
}
getTokenBalance(address, contractAddress, tokenTicker) {
return __awaiter(this, void 0, void 0, function* () {
const asset = {
chain: this.chain,
symbol: `${tokenTicker}-${contractAddress}`,
ticker: tokenTicker,
synth: false,
};
const contract = new ethers.Contract(contractAddress, erc20ABI, this.provider);
const balance = (yield contract.balanceOf(address)).toString();
const decimals = (yield contract.decimals()).toString();
const amount = baseAmount(balance, Number.parseInt(decimals));
return {
asset,
amount,
};
});
}
getUniqueContractAddresses(array) {
const mySet = new Set();
return array.filter((x) => {
const key = x.contractAddress, isNew = !mySet.has(key);
if (isNew)
mySet.add(key);
return isNew;
});
}
getTransactions(params) {
return __awaiter(this, void 0, void 0, function* () {
const offset = (params === null || params === void 0 ? void 0 : params.offset) || 0;
const limit = (params === null || params === void 0 ? void 0 : params.limit) || 10;
const assetAddress = params === null || params === void 0 ? void 0 : params.asset;
const maxCount = 10000;
let transactions;
if (assetAddress) {
transactions = yield getTokenTransactionHistory({
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
address: params === null || params === void 0 ? void 0 : params.address,
assetAddress,
page: 0,
offset: maxCount,
apiKey: this.apiKey,
chain: this.chain,
});
for (const provider of this.dataProviders) {
try {
const prov = provider[this.network];
if (prov)
return yield prov.getTransactionData(txId, assetAddress);
}
catch (error) {
console.warn(error);
}
}
else {
transactions = yield getGasAssetTransactionHistory({
gasAsset: this.nativeAsset,
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
address: params === null || params === void 0 ? void 0 : params.address,
page: 0,
offset: maxCount,
apiKey: this.apiKey,
});
}
return {
total: transactions.length,
txs: transactions.filter((_, index) => index >= offset && index < offset + limit),
};
throw Error('no provider able to GetTransactionData');
});
}
getTransactionData(txHash, assetAddress) {
var _a, _b;
roundRobinGetTransactions(params) {
return __awaiter(this, void 0, void 0, function* () {
let tx;
const txInfo = yield this.provider.getTransaction(txHash);
if (txInfo) {
if (assetAddress) {
tx =
(_a = (yield getTokenTransactionHistory({
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
assetAddress,
startblock: txInfo.blockNumber,
endblock: txInfo.blockNumber,
apiKey: this.apiKey,
chain: this.chain,
})).filter((info) => info.hash === txHash)[0]) !== null && _a !== void 0 ? _a : null;
for (const provider of this.dataProviders) {
try {
const prov = provider[this.network];
if (prov)
return yield prov.getTransactions(params);
}
else {
tx =
(_b = (yield getGasAssetTransactionHistory({
gasAsset: this.nativeAsset,
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
startblock: txInfo.blockNumber,
endblock: txInfo.blockNumber,
apiKey: this.apiKey,
address: txInfo.from,
})).filter((info) => info.hash === txHash)[0]) !== null && _b !== void 0 ? _b : null;
catch (error) {
console.warn(error);
}
}
if (!tx)
throw new Error('Could not get transaction history');
return tx;
throw Error('no provider able to GetTransactions');
});

@@ -1954,6 +1428,6 @@ }

router: routerABI,
erc20: erc20ABI$1,
erc20: erc20ABI,
};
export { Client, EtherscanProvider, MAX_APPROVAL, abi, call, estimateApprove, estimateCall, getApprovalAmount, getPrefix, getTokenAddress, isApproved, strip0x, validateAddress$1 as validateAddress };
export { Client, MAX_APPROVAL, abi, call, estimateApprove, estimateCall, getApprovalAmount, getPrefix, getTokenAddress, isApproved, strip0x, validateAddress };
//# sourceMappingURL=index.esm.js.map

@@ -9,8 +9,3 @@ 'use strict';

var utils = require('ethers/lib/utils');
var axios = require('axios');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
/******************************************************************************

@@ -41,3 +36,3 @@ Copyright (c) Microsoft Corporation.

var erc20ABI$1 = [
var erc20ABI = [
{

@@ -284,3 +279,3 @@ inputs: [

*/
const validateAddress$1 = (address) => {
const validateAddress = (address) => {
try {

@@ -398,3 +393,3 @@ ethers.ethers.utils.getAddress(address);

const txAmount = ethers.ethers.BigNumber.from((_a = amount === null || amount === void 0 ? void 0 : amount.amount().toFixed()) !== null && _a !== void 0 ? _a : 1);
const contract = new ethers.ethers.Contract(contractAddress, erc20ABI$1, provider);
const contract = new ethers.ethers.Contract(contractAddress, erc20ABI, provider);
const allowance = yield contract.allowance(fromAddress, spenderAddress);

@@ -560,3 +555,3 @@ return txAmount.lte(allowance);

validateAddress(address) {
return validateAddress$1(address);
return validateAddress(address);
}

@@ -573,6 +568,3 @@ /**

return __awaiter(this, void 0, void 0, function* () {
const prov = this.dataProviders[this.network];
if (!prov)
throw Error('Provider unidefined');
return yield prov.getBalance(address, assets);
return yield this.roundRobinGetBalance(address, assets);
});

@@ -596,6 +588,3 @@ }

};
const prov = this.dataProviders[this.network];
if (!prov)
throw Error('Provider unidefined');
return yield prov.getTransactions(filteredParams);
return yield this.roundRobinGetTransactions(filteredParams);
});

@@ -615,6 +604,3 @@ }

return __awaiter(this, void 0, void 0, function* () {
const prov = this.dataProviders[this.network];
if (!prov)
throw Error('Provider unidefined');
return yield prov.getTransactionData(txId, assetAddress);
return yield this.roundRobinGetTransactionData(txId, assetAddress);
});

@@ -716,3 +702,3 @@ }

const valueToApprove = getApprovalAmount(amount);
const contract = new ethers.ethers.Contract(contractAddress, erc20ABI$1, this.getProvider());
const contract = new ethers.ethers.Contract(contractAddress, erc20ABI, this.getProvider());
/* as same as ethers.TransactionResponse expected by `sendTransaction` */

@@ -742,3 +728,3 @@ const unsignedTx = yield contract.populateTransaction.approve(spenderAddress, valueToApprove);

fromAddress,
abi: erc20ABI$1,
abi: erc20ABI,
amount,

@@ -809,3 +795,3 @@ });

contractAddress: assetAddress,
abi: erc20ABI$1,
abi: erc20ABI,
funcName: 'transfer',

@@ -886,3 +872,3 @@ funcParams: [recipient, txAmount, Object.assign({}, overrides)],

throw Error(`Can't get address from asset ${xchainUtil.assetToString(theAsset)}`);
const contract = new ethers.ethers.Contract(assetAddress, erc20ABI$1, this.getProvider());
const contract = new ethers.ethers.Contract(assetAddress, erc20ABI, this.getProvider());
gasEstimate = yield contract.estimateGas.transfer(recipient, txAmount, {

@@ -947,561 +933,45 @@ from: this.getAddress(),

}
}
var erc20ABI = [
{
inputs: [
],
stateMutability: "nonpayable",
type: "constructor"
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "owner",
type: "address"
},
{
indexed: true,
internalType: "address",
name: "spender",
type: "address"
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "Approval",
type: "event"
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "from",
type: "address"
},
{
indexed: true,
internalType: "address",
name: "to",
type: "address"
},
{
indexed: false,
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "Transfer",
type: "event"
},
{
inputs: [
{
internalType: "address",
name: "",
type: "address"
},
{
internalType: "address",
name: "",
type: "address"
}
],
name: "allowance",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "spender",
type: "address"
},
{
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "approve",
outputs: [
{
internalType: "bool",
name: "success",
type: "bool"
}
],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "",
type: "address"
}
],
name: "balanceOf",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "decimals",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "name",
outputs: [
{
internalType: "string",
name: "",
type: "string"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "symbol",
outputs: [
{
internalType: "string",
name: "",
type: "string"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
],
name: "totalSupply",
outputs: [
{
internalType: "uint256",
name: "",
type: "uint256"
}
],
stateMutability: "view",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "to",
type: "address"
},
{
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "transfer",
outputs: [
{
internalType: "bool",
name: "success",
type: "bool"
}
],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{
internalType: "address",
name: "from",
type: "address"
},
{
internalType: "address",
name: "to",
type: "address"
},
{
internalType: "uint256",
name: "value",
type: "uint256"
}
],
name: "transferFrom",
outputs: [
{
internalType: "bool",
name: "success",
type: "bool"
}
],
stateMutability: "nonpayable",
type: "function"
}
];
ethers.ethers.BigNumber.from(2).pow(256).sub(1);
/**
* Validate the given address.
*
* @param {Address} address
* @returns {boolean} `true` or `false`
*/
const validateAddress = (address) => {
try {
ethers.ethers.utils.getAddress(address);
return true;
}
catch (error) {
return false;
}
};
const getApiKeyQueryParameter = (apiKey) => (!!apiKey ? `&apiKey=${apiKey}` : '');
/**
* Filter self txs
*
* @returns {T[]}
*
**/
const filterSelfTxs = (txs) => {
const filterTxs = txs.filter((tx) => tx.from !== tx.to);
let selfTxs = txs.filter((tx) => tx.from === tx.to);
while (selfTxs.length) {
const selfTx = selfTxs[0];
filterTxs.push(selfTx);
selfTxs = selfTxs.filter((tx) => tx.hash !== selfTx.hash);
}
return filterTxs;
};
/**
* Check if the symbol is valid.
*
* @param {string|null|undefined} symbol
* @returns {boolean} `true` or `false`.
*/
const validateSymbol = (symbol) => (symbol ? symbol.length >= 3 : false);
/**
* Get transactions from ETH transaction
*
* @param {ETHTransactionInfo} tx
* @returns {Tx} The parsed transaction.
*/
const getTxFromEthTransaction = (tx, gasAsset, decimals) => {
return {
asset: gasAsset,
from: [
{
from: tx.from,
amount: xchainUtil.baseAmount(tx.value, decimals),
},
],
to: [
{
to: tx.to,
amount: xchainUtil.baseAmount(tx.value, decimals),
},
],
date: new Date(parseInt(tx.timeStamp) * 1000),
type: xchainClient.TxType.Transfer,
hash: tx.hash,
};
};
/**
* Get transactions from token tx
*
* @param {TokenTransactionInfo} tx
* @returns {Tx|null} The parsed transaction.
*/
const getTxFromTokenTransaction = (tx, chain, decimals) => {
const decimal = parseInt(tx.tokenDecimal) || decimals;
const symbol = tx.tokenSymbol;
const address = tx.contractAddress;
if (validateSymbol(symbol) && validateAddress(address)) {
const tokenAsset = xchainUtil.assetFromString(`${chain}.${symbol}-${address}`);
if (tokenAsset) {
return {
asset: tokenAsset,
from: [
{
from: tx.from,
amount: xchainUtil.baseAmount(tx.value, decimal),
},
],
to: [
{
to: tx.to,
amount: xchainUtil.baseAmount(tx.value, decimal),
},
],
date: new Date(parseInt(tx.timeStamp) * 1000),
type: xchainClient.TxType.Transfer,
hash: tx.hash,
};
}
}
return null;
};
/**
* 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
*/
const getGasAssetTransactionHistory = ({ gasAsset, gasDecimals, baseUrl, address, page, offset, startblock, endblock, apiKey, }) => __awaiter(void 0, void 0, void 0, function* () {
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 = (yield axios__default["default"].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) => !xchainUtil.bnOrZero(tx.value).isZero())
.map((tx) => getTxFromEthTransaction(tx, gasAsset, gasDecimals));
});
/**
* 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
*/
const getTokenTransactionHistory = ({ gasDecimals, baseUrl, address, assetAddress, page, offset, startblock, endblock, apiKey, chain, }) => __awaiter(void 0, void 0, void 0, function* () {
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 = (yield axios__default["default"].get(url)).data.result;
if (JSON.stringify(result).includes('Invalid API Key'))
throw new Error('Invalid API Key');
return filterSelfTxs(result)
.filter((tx) => !xchainUtil.bnOrZero(tx.value).isZero())
.reduce((acc, cur) => {
const tx = getTxFromTokenTransaction(cur, chain, gasDecimals);
return tx ? [...acc, tx] : acc;
}, []);
});
class EtherscanProvider {
constructor(provider, baseUrl, apiKey, chain, nativeAsset, nativeAssetDecimals) {
this.provider = provider;
this.baseUrl = baseUrl;
this.apiKey = apiKey;
this.chain = chain;
this.nativeAsset = nativeAsset;
this.nativeAssetDecimals = nativeAssetDecimals;
this.nativeAsset;
this.chain;
}
getBalance(address, assets) {
roundRobinGetBalance(address, assets) {
return __awaiter(this, void 0, void 0, function* () {
//validate assets are for the correct chain
assets === null || assets === void 0 ? void 0 : assets.forEach((i) => {
if (i.chain !== this.chain)
throw Error(`${xchainUtil.assetToString(i)} is not an asset of ${this.chain}`);
});
const balances = [];
if (assets) {
for (const asset of assets) {
if (asset.symbol === this.nativeAsset.symbol) {
balances.push(yield this.getNativeAssetBalance(address));
}
else {
const splitSymbol = asset.symbol.split('-');
const tokenSymbol = splitSymbol[0];
const contractAddress = splitSymbol[1];
balances.push(yield this.getTokenBalance(address, contractAddress, tokenSymbol));
}
for (const provider of this.dataProviders) {
try {
const prov = provider[this.network];
if (prov)
return yield prov.getBalance(address, assets);
}
}
else {
//get nativeAsset
balances.push(yield this.getNativeAssetBalance(address));
// Get All Erc-20 txs
const response = (yield axios__default["default"].get(`${this.baseUrl}/api?module=account&action=tokentx&address=${address}&startblock=0&sort=asc&apikey=${this.apiKey}`)).data;
const erc20TokenTxs = this.getUniqueContractAddresses(response.result);
for (const erc20Token of erc20TokenTxs) {
balances.push(yield this.getTokenBalance(address, erc20Token.contractAddress, erc20Token.tokenSymbol));
catch (error) {
console.warn(error);
}
}
return balances;
throw Error('no provider able to get balance');
});
}
getNativeAssetBalance(address) {
roundRobinGetTransactionData(txId, assetAddress) {
return __awaiter(this, void 0, void 0, function* () {
const gasAssetBalance = yield this.provider.getBalance(address);
const amount = xchainUtil.baseAmount(gasAssetBalance.toString(), this.nativeAssetDecimals);
return {
asset: this.nativeAsset,
amount,
};
});
}
getTokenBalance(address, contractAddress, tokenTicker) {
return __awaiter(this, void 0, void 0, function* () {
const asset = {
chain: this.chain,
symbol: `${tokenTicker}-${contractAddress}`,
ticker: tokenTicker,
synth: false,
};
const contract = new ethers.ethers.Contract(contractAddress, erc20ABI, this.provider);
const balance = (yield contract.balanceOf(address)).toString();
const decimals = (yield contract.decimals()).toString();
const amount = xchainUtil.baseAmount(balance, Number.parseInt(decimals));
return {
asset,
amount,
};
});
}
getUniqueContractAddresses(array) {
const mySet = new Set();
return array.filter((x) => {
const key = x.contractAddress, isNew = !mySet.has(key);
if (isNew)
mySet.add(key);
return isNew;
});
}
getTransactions(params) {
return __awaiter(this, void 0, void 0, function* () {
const offset = (params === null || params === void 0 ? void 0 : params.offset) || 0;
const limit = (params === null || params === void 0 ? void 0 : params.limit) || 10;
const assetAddress = params === null || params === void 0 ? void 0 : params.asset;
const maxCount = 10000;
let transactions;
if (assetAddress) {
transactions = yield getTokenTransactionHistory({
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
address: params === null || params === void 0 ? void 0 : params.address,
assetAddress,
page: 0,
offset: maxCount,
apiKey: this.apiKey,
chain: this.chain,
});
for (const provider of this.dataProviders) {
try {
const prov = provider[this.network];
if (prov)
return yield prov.getTransactionData(txId, assetAddress);
}
catch (error) {
console.warn(error);
}
}
else {
transactions = yield getGasAssetTransactionHistory({
gasAsset: this.nativeAsset,
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
address: params === null || params === void 0 ? void 0 : params.address,
page: 0,
offset: maxCount,
apiKey: this.apiKey,
});
}
return {
total: transactions.length,
txs: transactions.filter((_, index) => index >= offset && index < offset + limit),
};
throw Error('no provider able to GetTransactionData');
});
}
getTransactionData(txHash, assetAddress) {
var _a, _b;
roundRobinGetTransactions(params) {
return __awaiter(this, void 0, void 0, function* () {
let tx;
const txInfo = yield this.provider.getTransaction(txHash);
if (txInfo) {
if (assetAddress) {
tx =
(_a = (yield getTokenTransactionHistory({
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
assetAddress,
startblock: txInfo.blockNumber,
endblock: txInfo.blockNumber,
apiKey: this.apiKey,
chain: this.chain,
})).filter((info) => info.hash === txHash)[0]) !== null && _a !== void 0 ? _a : null;
for (const provider of this.dataProviders) {
try {
const prov = provider[this.network];
if (prov)
return yield prov.getTransactions(params);
}
else {
tx =
(_b = (yield getGasAssetTransactionHistory({
gasAsset: this.nativeAsset,
gasDecimals: this.nativeAssetDecimals,
baseUrl: this.baseUrl,
startblock: txInfo.blockNumber,
endblock: txInfo.blockNumber,
apiKey: this.apiKey,
address: txInfo.from,
})).filter((info) => info.hash === txHash)[0]) !== null && _b !== void 0 ? _b : null;
catch (error) {
console.warn(error);
}
}
if (!tx)
throw new Error('Could not get transaction history');
return tx;
throw Error('no provider able to GetTransactions');
});

@@ -1963,7 +1433,6 @@ }

router: routerABI,
erc20: erc20ABI$1,
erc20: erc20ABI,
};
exports.Client = Client;
exports.EtherscanProvider = EtherscanProvider;
exports.MAX_APPROVAL = MAX_APPROVAL;

@@ -1979,3 +1448,3 @@ exports.abi = abi;

exports.strip0x = strip0x;
exports.validateAddress = validateAddress$1;
exports.validateAddress = validateAddress;
//# sourceMappingURL=index.js.map
{
"name": "@xchainjs/xchain-evm",
"version": "0.2.2",
"version": "0.3.0",
"description": "Genereic EVM client for XChainJS",

@@ -40,2 +40,3 @@ "keywords": [

"@xchainjs/xchain-util": "^0.13.0",
"@xchainjs/xchain-evm-providers": "^0.1.0",
"axios": "^1.3.6",

@@ -51,2 +52,2 @@ "ethers": "^5.7.2"

}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc