Code:function transform(input) {
var BATCH_SIZE = 250;
var contractAddr = (input.contractAddress || '').toLowerCase();
var now = new Date();
var cutoff = new Date(now.getTime() - 24 * 60 * 60 * 1000);
var nowIso = now.toISOString();
var decimalsMap = {};
var symbolMap = {};
var tokenAddresses = input.tokenAddresses || [];
var iterations = input.decimalsIterations || [];
for (var d = 0; d < iterations.length; d++) {
var iter = iterations[d];
var meta = iter && iter['get-token-meta'];
if (meta && tokenAddresses[d]) {
var addr = tokenAddresses[d].toLowerCase();
decimalsMap[addr] = meta.decimals !== undefined ? meta.decimals : 18;
symbolMap[addr] = meta.symbol || '';
}
}
var existingHashes = {};
var dbRows = input.existingHashes || [];
for (var h = 0; h < dbRows.length; h++) {
if (dbRows[h] && dbRows[h].tx_hash) existingHashes[dbRows[h].tx_hash.toLowerCase()] = true;
}
var allTxs = (input.transactions || []).filter(function(tx) {
if (!tx.blockTime) return false;
return new Date(tx.blockTime) >= cutoff;
});
var txs = allTxs.filter(function(tx) {
return !existingHashes[(tx.hash || '').toLowerCase()];
});
txs.sort(function(a, b) {
return new Date(a.blockTime) - new Date(b.blockTime);
});
var eventRows = [];
var txRows = [];
var uniqueSet = {};
var totalInflow = 0;
var totalOutflow = 0;
var newHashes = [];
for (var t = 0; t < txs.length; t++) {
var tx = txs[t];
var txFrom = (tx.from || '').toLowerCase();
var txTo = (tx.to || '').toLowerCase();
uniqueSet[txFrom] = true;
if (txTo) uniqueSet[txTo] = true;
newHashes.push({hash: tx.hash || '', block: tx.blockNumber || 0});
var transferCount = 0;
if (tx.logs && tx.logs.length > 0) {
for (var li = 0; li < tx.logs.length; li++) {
var log = tx.logs[li];
var eventName = (log.decoded && log.decoded.name) ? log.decoded.name : 'Unknown';
var logInputs = (log.decoded && log.decoded.inputs) ? log.decoded.inputs : [];
var fromAddr = '';
var toAddr = '';
var rawValue = '';
var direction = '';
var valNormalized = '';
var tokenAddr = (log.address || '').toLowerCase();
var decimals = decimalsMap[tokenAddr] !== undefined ? decimalsMap[tokenAddr] : 18;
var symbol = symbolMap[tokenAddr] || '';
if (eventName === 'Transfer') {
var addresses = [];
var amounts = [];
for (var j = 0; j < logInputs.length; j++) {
var inp = logInputs[j];
if (inp.type === 'address') addresses.push(String(inp.value || ''));
if (inp.type && inp.type.indexOf('uint') === 0) amounts.push(String(inp.value || ''));
}
fromAddr = addresses[0] || '';
toAddr = addresses[1] || '';
rawValue = amounts[0] || '';
} else {
for (var j = 0; j < logInputs.length; j++) {
var inp = logInputs[j];
if (inp.name === 'from' || inp.name === '_from' || inp.name === 'owner' || inp.name === 'tokenOwner' || inp.name === 'sender' || inp.name === 'src' || inp.name === '_src') fromAddr = String(inp.value || '');
if (inp.name === 'to' || inp.name === '_to' || inp.name === 'spender' || inp.name === 'dst' || inp.name === 'receiver' || inp.name === '_dst') toAddr = String(inp.value || '');
if (inp.name === 'value' || inp.name === '_value' || inp.name === 'amount' || inp.name === 'wad' || inp.name === 'tokens' || inp.name === '_tokens' || inp.name === '_amount') rawValue = String(inp.value || '');
}
}
if (eventName === 'Transfer' && rawValue) {
transferCount++;
direction = toAddr.toLowerCase() === contractAddr ? 'inbound' : 'outbound';
var valNum = Number(rawValue) / Math.pow(10, decimals);
valNormalized = valNum.toString();
if (direction === 'inbound') totalInflow += valNum;
else totalOutflow += valNum;
}
eventRows.push([
String(tx.blockNumber || ''),
tx.blockTime || '',
tx.hash || '',
String(li),
eventName,
fromAddr,
toAddr,
log.address || '',
symbol,
String(decimals),
rawValue,
valNormalized,
direction
]);
}
} else {
eventRows.push([
String(tx.blockNumber || ''),
tx.blockTime || '',
tx.hash || '',
'',
tx.decoded ? tx.decoded.name : 'contract call',
txFrom,
txTo,
'',
'',
'',
'',
'',
txTo === contractAddr ? 'inbound' : 'outbound'
]);
}
var txVal = 0;
if (tx.value) { try { txVal = parseInt(tx.value, 16); } catch(e) { txVal = 0; } }
var valEth = txVal / 1e18;
var gasUsed = 0;
if (tx.gasUsed) { try { gasUsed = parseInt(tx.gasUsed, 16); } catch(e) {} }
var gasPrice = 0;
if (tx.effectiveGasPrice) { try { gasPrice = parseInt(tx.effectiveGasPrice, 16); } catch(e) {} }
var txFee = (gasUsed * gasPrice) / 1e18;
txRows.push([
tx.hash || '',
String(tx.blockNumber || ''),
tx.blockTime || '',
tx.from || '',
tx.to || '',
valEth.toString(),
txFee.toFixed(8),
(gasPrice / 1e9).toFixed(4) + ' gwei',
String(transferCount)
]);
}
var insertRecords = [];
for (var k = 0; k < newHashes.length; k++) {
insertRecords.push({hash: newHashes[k].hash, block: newHashes[k].block, ts: nowIso});
}
var uniqueAddrs = Object.keys(uniqueSet);
var hasMore = input.hasMore || false;
var eventRowBatches = [];
for (var b = 0; b < eventRows.length; b += BATCH_SIZE) {
eventRowBatches.push(eventRows.slice(b, b + BATCH_SIZE));
}
var txRowBatches = [];
for (var b = 0; b < txRows.length; b += BATCH_SIZE) {
txRowBatches.push(txRows.slice(b, b + BATCH_SIZE));
}
return {
eventRowBatches: eventRowBatches,
txRowBatches: txRowBatches,
insertRecordsJson: JSON.stringify(insertRecords),
hasNewTxs: newHashes.length > 0,
totalTxs: txs.length,
skippedDuplicates: allTxs.length - txs.length,
totalInflow: totalInflow.toFixed(6),
totalOutflow: totalOutflow.toFixed(6),
uniqueAddressCount: uniqueAddrs.length,
uniqueAddresses: uniqueAddrs.slice(0, 50).join(', '),
hasMore: hasMore
};
}
Input:{"contractAddress":"{{$props.contractAddress}}","decimalsIterations":"{{fetch-decimals.result.iterations}}","existingHashes":"{{check-existing.result.rows}}","hasMore":"{{fetch-txs.result.hasMore}}","tokenAddresses":"{{extract-hashes.result.output.tokenAddresses}}","transactions":"{{fetch-txs.result.transactions}}"}