Compare commits
5 Commits
54831c71bc
...
a2105fc970
| Author | SHA1 | Date | |
|---|---|---|---|
| a2105fc970 | |||
| d106eb516d | |||
| 8c768f0081 | |||
| 1125e65ed4 | |||
| 1aa07f35e5 |
@ -1054,6 +1054,11 @@ aside h4 {
|
||||
display: none; /* Chrome, Safari and Opera */
|
||||
}
|
||||
|
||||
#tx_filter_chips sm-chip {
|
||||
font-size: 0.75rem;
|
||||
--padding: 0.3rem 0.6rem;
|
||||
}
|
||||
|
||||
#error_section {
|
||||
display: grid;
|
||||
height: 100%;
|
||||
|
||||
175
index.html
175
index.html
@ -822,56 +822,80 @@
|
||||
loadTransactionsPage(ethAddress, floAddress, currentPage);
|
||||
}
|
||||
|
||||
let allTransactionsCache = [];
|
||||
let currentFilter = 'all';
|
||||
let currentBalances = { eth: '0', usdc: '0', usdt: '0' };
|
||||
|
||||
async function loadTransactionsPage(ethAddress, floAddress, page) {
|
||||
buttonLoader('check_balance_button', true);
|
||||
|
||||
try {
|
||||
const results = await Promise.allSettled([
|
||||
ethOperator.getBalance(ethAddress),
|
||||
ethOperator.getTokenBalance(ethAddress, 'usdc'),
|
||||
ethOperator.getTokenBalance(ethAddress, 'usdt'),
|
||||
ethOperator.getTransactionHistory(ethAddress, {
|
||||
page: page,
|
||||
offset: TRANSACTIONS_PER_PAGE,
|
||||
sort: 'desc'
|
||||
let transactions = [];
|
||||
let etherBalance = '0', usdcBalance = '0', usdtBalance = '0';
|
||||
|
||||
// Fetch new data if it's the first page (Search or Refresh)
|
||||
if (page === 1) {
|
||||
const results = await Promise.allSettled([
|
||||
ethOperator.getBalance(ethAddress),
|
||||
ethOperator.getTokenBalance(ethAddress, 'usdc'),
|
||||
ethOperator.getTokenBalance(ethAddress, 'usdt'),
|
||||
ethOperator.getTransactionHistory(ethAddress, {
|
||||
page: 1, // Always Page 1 of API
|
||||
offset: 500, // Batch size 500
|
||||
sort: 'desc'
|
||||
})
|
||||
]);
|
||||
|
||||
etherBalance = results[0].status === 'fulfilled' ? results[0].value : '0';
|
||||
usdcBalance = results[1].status === 'fulfilled' ? results[1].value : '0';
|
||||
usdtBalance = results[2].status === 'fulfilled' ? results[2].value : '0';
|
||||
transactions = results[3].status === 'fulfilled' ? results[3].value : [];
|
||||
|
||||
// Update Cache
|
||||
allTransactionsCache = transactions;
|
||||
currentBalances = { eth: etherBalance, usdc: usdcBalance, usdt: usdtBalance };
|
||||
|
||||
// Log warnings
|
||||
if (results[0].status === 'rejected') console.warn('Failed to fetch ETH balance:', results[0].reason);
|
||||
if (results[1].status === 'rejected') console.warn('Failed to fetch USDC balance:', results[1].reason);
|
||||
if (results[2].status === 'rejected') console.warn('Failed to fetch USDT balance:', results[2].reason);
|
||||
if (results[3].status === 'rejected') console.warn('Failed to fetch transaction history:', results[3].reason);
|
||||
|
||||
} else {
|
||||
// Use Cache for pagination
|
||||
transactions = allTransactionsCache;
|
||||
({ eth: etherBalance, usdc: usdcBalance, usdt: usdtBalance } = currentBalances);
|
||||
}
|
||||
|
||||
// Filter interactions
|
||||
let filteredTransactions = transactions;
|
||||
if (currentFilter === 'sent') {
|
||||
filteredTransactions = transactions.filter(tx => tx.isSent);
|
||||
} else if (currentFilter === 'received') {
|
||||
filteredTransactions = transactions.filter(tx => tx.isReceived);
|
||||
}
|
||||
|
||||
// Local Pagination / Slicing
|
||||
const startIndex = (page - 1) * TRANSACTIONS_PER_PAGE;
|
||||
const endIndex = startIndex + TRANSACTIONS_PER_PAGE;
|
||||
const paginatedTransactions = filteredTransactions.slice(startIndex, endIndex);
|
||||
const hasNextPage = filteredTransactions.length > endIndex;
|
||||
|
||||
// Sync Contacts (only on fresh load really, but safe here)
|
||||
if (page === 1) {
|
||||
compactIDB.readData('contacts', floAddress || ethAddress).then(result => {
|
||||
if (result) return
|
||||
compactIDB.addData('contacts', {
|
||||
ethAddress,
|
||||
}, floAddress || ethAddress).then(() => {
|
||||
renderSearchedAddressList()
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
})
|
||||
]);
|
||||
|
||||
// Extract balance and transaction data, using defaults if any request failed
|
||||
const etherBalance = results[0].status === 'fulfilled' ? results[0].value : '0';
|
||||
const usdcBalance = results[1].status === 'fulfilled' ? results[1].value : '0';
|
||||
const usdtBalance = results[2].status === 'fulfilled' ? results[2].value : '0';
|
||||
const transactions = results[3].status === 'fulfilled' ? results[3].value : [];
|
||||
|
||||
// Store transactions for filtering
|
||||
allTransactions = transactions;
|
||||
|
||||
// Log warnings if any API requests failed
|
||||
if (results[0].status === 'rejected') {
|
||||
console.warn('Failed to fetch ETH balance:', results[0].reason);
|
||||
}
|
||||
if (results[1].status === 'rejected') {
|
||||
console.warn('Failed to fetch USDC balance:', results[1].reason);
|
||||
}
|
||||
if (results[2].status === 'rejected') {
|
||||
console.warn('Failed to fetch USDT balance:', results[2].reason);
|
||||
}
|
||||
if (results[3].status === 'rejected') {
|
||||
console.warn('Failed to fetch transaction history:', results[3].reason);
|
||||
}
|
||||
|
||||
compactIDB.readData('contacts', floAddress || ethAddress).then(result => {
|
||||
if (result) return
|
||||
compactIDB.addData('contacts', {
|
||||
ethAddress,
|
||||
}, floAddress || ethAddress).then(() => {
|
||||
renderSearchedAddressList()
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
})
|
||||
})
|
||||
|
||||
renderBalanceAndTransactions(ethAddress, floAddress, etherBalance, usdcBalance, usdtBalance, transactions, page);
|
||||
renderBalanceAndTransactions(ethAddress, floAddress, etherBalance, usdcBalance, usdtBalance, paginatedTransactions, page, hasNextPage);
|
||||
|
||||
} catch (error) {
|
||||
notify(error.message || error, 'error');
|
||||
@ -880,7 +904,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function renderBalanceAndTransactions(ethAddress, floAddress, etherBalance, usdcBalance, usdtBalance, transactions, page) {
|
||||
function renderBalanceAndTransactions(ethAddress, floAddress, etherBalance, usdcBalance, usdtBalance, transactions, page, hasNextPage) {
|
||||
// Update URL to reflect the current address being viewed
|
||||
const url = new URL(window.location);
|
||||
url.searchParams.set('address', ethAddress);
|
||||
@ -890,7 +914,7 @@
|
||||
window.history.pushState({}, '', url.pathname + url.search + url.hash);
|
||||
|
||||
// Determine if pagination buttons should be enabled
|
||||
const hasNextPage = transactions.length >= TRANSACTIONS_PER_PAGE;
|
||||
// hasNextPage is now passed in
|
||||
const hasPrevPage = page > 1;
|
||||
|
||||
renderElem(getRef('eth_balance_wrapper'), html`
|
||||
@ -922,19 +946,21 @@
|
||||
</ul>
|
||||
</div>
|
||||
<div class="grid gap-1 margin-top-1">
|
||||
<div class="flex align-center space-between">
|
||||
<h4>Transactions</h4>
|
||||
<div class="flex align-center space-between gap-1" style="overflow-x: auto; white-space: nowrap; scrollbar-width: none; -ms-overflow-style: none;">
|
||||
<h4 class="flex-shrink-0">Transactions</h4>
|
||||
<sm-chips id="tx_filter_chips" onchange=${(e) => {
|
||||
const selectedValue = e.detail?.value || e.target.value || 'all';
|
||||
filterTransactions(selectedValue, transactions, ethAddress);
|
||||
currentFilter = selectedValue;
|
||||
currentPage = 1;
|
||||
loadTransactionsPage(ethAddress, floAddress, currentPage);
|
||||
}}>
|
||||
<sm-chip value="all" selected>All</sm-chip>
|
||||
<sm-chip value="sent">Sent</sm-chip>
|
||||
<sm-chip value="received">Received</sm-chip>
|
||||
<sm-chip value="all" ?selected=${currentFilter === 'all'}>All</sm-chip>
|
||||
<sm-chip value="sent" ?selected=${currentFilter === 'sent'}>Sent</sm-chip>
|
||||
<sm-chip value="received" ?selected=${currentFilter === 'received'}>Received</sm-chip>
|
||||
</sm-chips>
|
||||
</div>
|
||||
<ul id="transaction_list" class="grid gap-0-5">
|
||||
${renderTransactionList(transactions, ethAddress, 'all')}
|
||||
${renderTransactionList(transactions, ethAddress)}
|
||||
</ul>
|
||||
<div class="flex align-center space-between gap-1 margin-top-1">
|
||||
<button
|
||||
@ -985,23 +1011,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
function renderTransactionList(transactions, userAddress, filter = 'all') {
|
||||
function renderTransactionList(transactions, userAddress) {
|
||||
if (!transactions || transactions.length === 0) {
|
||||
return html`<li class="text-center color-0-8"><p>No transactions found</p></li>`;
|
||||
}
|
||||
|
||||
let filteredTxs = transactions;
|
||||
if (filter === 'sent') {
|
||||
filteredTxs = transactions.filter(tx => tx.isSent);
|
||||
} else if (filter === 'received') {
|
||||
filteredTxs = transactions.filter(tx => tx.isReceived);
|
||||
}
|
||||
|
||||
if (filteredTxs.length === 0) {
|
||||
return html`<li class="text-center color-0-8"><p>No ${filter} transactions found</p></li>`;
|
||||
}
|
||||
|
||||
return filteredTxs.map(tx => {
|
||||
return transactions.map(tx => {
|
||||
const date = new Date(tx.timestamp * 1000);
|
||||
const formattedDate = date.toLocaleString('en-US', {
|
||||
month: 'short',
|
||||
@ -1029,12 +1044,12 @@
|
||||
<li class=${className}>
|
||||
<div class="transaction__icon">${icon}</div>
|
||||
<div class="grid gap-0-5">
|
||||
<div class="flex gap-1">
|
||||
<div class="flex gap-1 flex-wrap space-between">
|
||||
<time class="transaction__time">${formattedDate}</time>
|
||||
<div class="transaction__amount">${amountPrefix}${tx.value.toFixed(8)} ${tx.symbol}</div>
|
||||
</div>
|
||||
<div class="transaction__receiver">
|
||||
${directionText} <a href="#" class="tx-participant wrap-around">${displayAddress}</a>
|
||||
${directionText} <a href="#" class="tx-participant wrap-around" onclick=${(e) => { e.preventDefault(); checkBalance(displayAddress); }}>${displayAddress}</a>
|
||||
</div>
|
||||
<div class="flex gap-0-5 flex-wrap align-center">
|
||||
<button class="button button--small gap-0-3 align-center button--colored transaction__id" onclick=${() => viewTransactionDetails(tx.hash)}>
|
||||
@ -1124,14 +1139,32 @@
|
||||
</div>
|
||||
|
||||
<div class="grid gap-0-5">
|
||||
<div class="label">To</div>
|
||||
<div class="label">To (Contract)</div>
|
||||
<sm-copy value=${txDetails.to}></sm-copy>
|
||||
</div>
|
||||
|
||||
${txDetails.tokenTransfer ? html`
|
||||
${txDetails.tokenTransfers && txDetails.tokenTransfers.length > 0 ? html`
|
||||
<div class="grid gap-0-5">
|
||||
<div class="label">Token Transfer</div>
|
||||
<strong>${txDetails.tokenTransfer.value} ${txDetails.tokenTransfer.symbol}</strong>
|
||||
<div class="label">Token Transfers</div>
|
||||
<div class="grid gap-0-5" style="padding: 0.75rem; background: rgba(var(--text-color), 0.05); border-radius: 0.5rem;">
|
||||
${txDetails.tokenTransfers.map((transfer, index) => html`
|
||||
<div class="grid gap-0-3" style="${index !== txDetails.tokenTransfers.length - 1 ? 'border-bottom: 1px solid rgba(var(--text-color), 0.1); padding-bottom: 0.75rem; margin-bottom: 0.25rem;' : ''}">
|
||||
<div class="flex space-between align-center">
|
||||
<strong>${transfer.value} ${transfer.symbol}</strong>
|
||||
</div>
|
||||
<div class="grid gap-0-5" style="font-size: 0.8rem;">
|
||||
<div class="grid gap-0">
|
||||
<span class="color-0-7">From</span>
|
||||
<sm-copy value=${transfer.from} style="--font-size: 0.8rem;"></sm-copy>
|
||||
</div>
|
||||
<div class="grid gap-0">
|
||||
<span class="color-0-7">To</span>
|
||||
<sm-copy value=${transfer.to} style="--font-size: 0.8rem;"></sm-copy>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`)}
|
||||
</div>
|
||||
</div>
|
||||
` : html`
|
||||
<div class="grid gap-0-5">
|
||||
|
||||
@ -257,7 +257,7 @@
|
||||
try {
|
||||
if (!address || !isValidAddress(address))
|
||||
return new Error('Invalid address');
|
||||
|
||||
|
||||
// Use read-only provider (public RPC) for balance checks
|
||||
const provider = getProvider(true);
|
||||
const balanceWei = await provider.getBalance(address);
|
||||
@ -274,7 +274,7 @@
|
||||
return new Error("Token not specified");
|
||||
if (!CONTRACT_ADDRESSES[token] && contractAddress)
|
||||
return new Error('Contract address of token not available')
|
||||
|
||||
|
||||
// Use read-only provider (public RPC) for token balance checks
|
||||
const provider = getProvider(true);
|
||||
const tokenAddress = CONTRACT_ADDRESSES[token] || contractAddress;
|
||||
@ -307,17 +307,17 @@
|
||||
const provider = getProvider();
|
||||
const signer = new ethers.Wallet(privateKey, provider);
|
||||
const limit = await estimateGas({ privateKey, receiver, amount })
|
||||
|
||||
|
||||
// Get current fee data from the network
|
||||
const feeData = await provider.getFeeData();
|
||||
|
||||
|
||||
// Calculate priority fee (tip to miners) - use 1.5 gwei or the network's suggested priority fee, whichever is higher
|
||||
const priorityFee = feeData.maxPriorityFeePerGas || ethers.utils.parseUnits("1.5", "gwei");
|
||||
|
||||
|
||||
// Calculate max fee per gas (base fee + priority fee)
|
||||
// Use the network's suggested maxFeePerGas or calculate it manually
|
||||
let maxFee = feeData.maxFeePerGas;
|
||||
|
||||
|
||||
// If maxFeePerGas is not available or is less than priority fee, calculate it
|
||||
if (!maxFee || maxFee.lt(priorityFee)) {
|
||||
// Get the base fee from the latest block and add our priority fee
|
||||
@ -326,13 +326,13 @@
|
||||
// maxFee = (baseFee * 2) + priorityFee to account for potential base fee increases
|
||||
maxFee = baseFee.mul(2).add(priorityFee);
|
||||
}
|
||||
|
||||
|
||||
// Ensure maxFee is at least 1.5x the priority fee for safety
|
||||
const minMaxFee = priorityFee.mul(15).div(10); // 1.5x priority fee
|
||||
if (maxFee.lt(minMaxFee)) {
|
||||
maxFee = minMaxFee;
|
||||
}
|
||||
|
||||
|
||||
// Creating and sending the transaction object
|
||||
return signer.sendTransaction({
|
||||
to: receiver,
|
||||
@ -365,8 +365,8 @@
|
||||
return tokenContract.transfer(receiver, amountWei)
|
||||
}
|
||||
|
||||
|
||||
const ETHERSCAN_API_KEY = 'M3YBAHI21FVE7VS2FEKU6ZFGRA128WUVQK';
|
||||
|
||||
const ETHERSCAN_API_KEY = 'M3YBAHI21FVE7VS2FEKU6ZFGRA128WUVQK';
|
||||
|
||||
/**
|
||||
* Get transaction history for an Ethereum address
|
||||
@ -390,7 +390,7 @@
|
||||
|
||||
// Fetch normal transactions using V2 API
|
||||
const normalTxUrl = `https://api.etherscan.io/v2/api?chainid=1&module=account&action=txlist&address=${address}&startblock=${startBlock}&endblock=${endBlock}&page=${page}&offset=${offset}&sort=${sort}&apikey=${ETHERSCAN_API_KEY}`;
|
||||
|
||||
|
||||
const normalTxResponse = await fetch(normalTxUrl);
|
||||
const normalTxData = await normalTxResponse.json();
|
||||
|
||||
@ -410,15 +410,29 @@
|
||||
|
||||
// Fetch ERC20 token transfers using V2 API
|
||||
const tokenTxUrl = `https://api.etherscan.io/v2/api?chainid=1&module=account&action=tokentx&address=${address}&startblock=${startBlock}&endblock=${endBlock}&page=${page}&offset=${offset}&sort=${sort}&apikey=${ETHERSCAN_API_KEY}`;
|
||||
|
||||
|
||||
const tokenTxResponse = await fetch(tokenTxUrl);
|
||||
const tokenTxData = await tokenTxResponse.json();
|
||||
|
||||
const tokenTransfers = tokenTxData.status === '1' ? tokenTxData.result : [];
|
||||
const allowedTokenAddresses = Object.values(CONTRACT_ADDRESSES).map(addr => addr.toLowerCase());
|
||||
const rawTokenTransfers = tokenTxData.status === '1' ? tokenTxData.result : [];
|
||||
const tokenTransfers = rawTokenTransfers.filter(tx =>
|
||||
allowedTokenAddresses.includes(tx.contractAddress.toLowerCase()) && tx.value !== '0'
|
||||
);
|
||||
|
||||
// Combine and sort transactions
|
||||
const allTransactions = [...normalTxData.result, ...tokenTransfers];
|
||||
|
||||
// Filter out normal transactions that are already present in token transfers (duplicate hash) AND have 0 value
|
||||
// This prevents showing "0 ETH to Contract" alongside the actual "Token Transfer"
|
||||
const tokenTxHashes = new Set(tokenTransfers.map(tx => tx.hash));
|
||||
const uniqueNormalTxs = normalTxData.result.filter(tx => {
|
||||
if (tokenTxHashes.has(tx.hash) && tx.value === '0') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
const allTransactions = [...uniqueNormalTxs, ...tokenTransfers];
|
||||
|
||||
// Sort by timestamp (descending)
|
||||
allTransactions.sort((a, b) => parseInt(b.timeStamp) - parseInt(a.timeStamp));
|
||||
|
||||
@ -427,9 +441,9 @@
|
||||
return allTransactions.map(tx => {
|
||||
const isTokenTransfer = tx.tokenSymbol !== undefined;
|
||||
const isReceived = tx.to.toLowerCase() === address.toLowerCase();
|
||||
|
||||
|
||||
let value, symbol, decimals;
|
||||
|
||||
|
||||
if (isTokenTransfer) {
|
||||
decimals = parseInt(tx.tokenDecimal) || 18;
|
||||
value = parseFloat(ethers.utils.formatUnits(tx.value, decimals));
|
||||
@ -480,57 +494,75 @@
|
||||
|
||||
// Use read-only provider for fetching transaction details
|
||||
const provider = getProvider(true);
|
||||
|
||||
|
||||
// Get transaction details
|
||||
const tx = await provider.getTransaction(txHash);
|
||||
|
||||
|
||||
if (!tx) {
|
||||
throw new Error('Transaction not found');
|
||||
}
|
||||
|
||||
// Get transaction receipt for status and gas used
|
||||
const receipt = await provider.getTransactionReceipt(txHash);
|
||||
|
||||
|
||||
// Get current block number for confirmations
|
||||
const currentBlock = await provider.getBlockNumber();
|
||||
|
||||
|
||||
// Get block details for timestamp
|
||||
const block = await provider.getBlock(tx.blockNumber);
|
||||
|
||||
// Calculate gas fee
|
||||
const gasUsed = receipt ? receipt.gasUsed : null;
|
||||
const effectiveGasPrice = receipt ? receipt.effectiveGasPrice : tx.gasPrice;
|
||||
const gasFee = gasUsed && effectiveGasPrice ?
|
||||
const gasFee = gasUsed && effectiveGasPrice ?
|
||||
parseFloat(ethers.utils.formatEther(gasUsed.mul(effectiveGasPrice))) : null;
|
||||
|
||||
// Check if it's a token transfer by examining logs
|
||||
let tokenTransfer = null;
|
||||
let tokenTransfers = [];
|
||||
// Simple in-memory cache for token metadata to avoid rate limiting
|
||||
const TOKEN_METADATA_CACHE = ethOperator.TOKEN_METADATA_CACHE || {};
|
||||
ethOperator.TOKEN_METADATA_CACHE = TOKEN_METADATA_CACHE;
|
||||
|
||||
if (receipt && receipt.logs.length > 0) {
|
||||
// Try to decode ERC20 Transfer event
|
||||
const transferEventSignature = ethers.utils.id('Transfer(address,address,uint256)');
|
||||
const transferLog = receipt.logs.find(log => log.topics[0] === transferEventSignature);
|
||||
|
||||
if (transferLog) {
|
||||
const transferLogs = receipt.logs.filter(log => log.topics[0] === transferEventSignature);
|
||||
|
||||
if (transferLogs.length > 0) {
|
||||
try {
|
||||
const tokenContract = new ethers.Contract(transferLog.address, ERC20ABI, provider);
|
||||
const [symbol, decimals] = await Promise.all([
|
||||
tokenContract.symbol().catch(() => 'TOKEN'),
|
||||
tokenContract.decimals().catch(() => 18)
|
||||
]);
|
||||
|
||||
const from = ethers.utils.getAddress('0x' + transferLog.topics[1].slice(26));
|
||||
const to = ethers.utils.getAddress('0x' + transferLog.topics[2].slice(26));
|
||||
const value = parseFloat(ethers.utils.formatUnits(transferLog.data, decimals));
|
||||
|
||||
tokenTransfer = {
|
||||
from,
|
||||
to,
|
||||
value,
|
||||
symbol,
|
||||
contractAddress: transferLog.address
|
||||
};
|
||||
// Process all transfer logs
|
||||
tokenTransfers = await Promise.all(transferLogs.map(async (transferLog) => {
|
||||
const contractAddress = transferLog.address;
|
||||
let symbol, decimals;
|
||||
|
||||
// Check cache first
|
||||
if (TOKEN_METADATA_CACHE[contractAddress]) {
|
||||
({ symbol, decimals } = TOKEN_METADATA_CACHE[contractAddress]);
|
||||
} else {
|
||||
// Fetch from network if not cached
|
||||
const tokenContract = new ethers.Contract(contractAddress, ERC20ABI, provider);
|
||||
[symbol, decimals] = await Promise.all([
|
||||
tokenContract.symbol().catch(() => 'TOKEN'),
|
||||
tokenContract.decimals().catch(() => 18)
|
||||
]);
|
||||
// Store in cache
|
||||
TOKEN_METADATA_CACHE[contractAddress] = { symbol, decimals };
|
||||
}
|
||||
|
||||
const from = ethers.utils.getAddress('0x' + transferLog.topics[1].slice(26));
|
||||
const to = ethers.utils.getAddress('0x' + transferLog.topics[2].slice(26));
|
||||
const value = parseFloat(ethers.utils.formatUnits(transferLog.data, decimals));
|
||||
|
||||
return {
|
||||
from,
|
||||
to,
|
||||
value,
|
||||
symbol,
|
||||
contractAddress
|
||||
};
|
||||
}));
|
||||
} catch (e) {
|
||||
console.warn('Could not decode token transfer:', e);
|
||||
console.warn('Could not decode token transfers:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -552,7 +584,7 @@
|
||||
input: tx.data,
|
||||
status: receipt ? (receipt.status === 1 ? 'success' : 'failed') : 'pending',
|
||||
isError: receipt ? receipt.status !== 1 : false,
|
||||
tokenTransfer: tokenTransfer,
|
||||
tokenTransfers: tokenTransfers,
|
||||
logs: receipt ? receipt.logs : [],
|
||||
type: tx.type
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user