#!/usr/bin/env node /** * One-shot: record all txs in a Chain 138 block on AddressActivityRegistry (+ optional v1 mirror). */ import { ethers } from 'ethers'; import { usdStringToE8 } from '@dbis/checkpoint-core'; import { dualWriteV1Mirror } from './dualMirror'; import { recordActivityBatch } from './activityRegistry'; import { recordIsoAttestationBatch } from './activityRegistryV2'; import { attachIso20022ToLeaves } from './iso20022Enrich'; import { fetchReceiptMeta } from './receiptsRoot'; import { enrichLeafFromBlockscoutApi, enrichLeafUsd } from './usdEnrich'; import type { PaymentLeaf } from './ingress/types.js'; function arg(name: string): string | undefined { const i = process.argv.indexOf(`--${name}`); return i >= 0 ? process.argv[i + 1] : undefined; } async function main() { const block = parseInt(arg('block') || '0', 10); const batchId = BigInt(arg('batch-id') || '0'); const registry = arg('registry') || ''; const rpc138 = arg('rpc138') || 'http://192.168.11.211:8545'; const rpc1 = arg('rpc1') || 'https://ethereum-rpc.publicnode.com'; const mirror = arg('mirror') || ''; const dualMirror = process.argv.includes('--dual-mirror'); const dryRun = process.argv.includes('--dry-run'); const pk = process.env.PRIVATE_KEY; if (!pk && !dryRun) throw new Error('PRIVATE_KEY required (or pass --dry-run)'); if (!registry && !dryRun) throw new Error('--registry required'); const chain138 = new ethers.JsonRpcProvider(rpc138); const blk = await chain138.getBlock(block, true); if (!blk) throw new Error(`block ${block} not found`); const leaves: PaymentLeaf[] = []; const entries = blk.prefetchedTransactions?.length ? blk.prefetchedTransactions : blk.transactions ?? []; for (const entry of entries) { const tx = typeof entry === 'string' ? await chain138.getTransaction(entry) : entry; if (!tx || typeof tx === 'string') continue; const receipt = await chain138.getTransactionReceipt(tx.hash); const meta = await fetchReceiptMeta(chain138, tx.hash); const leaf: PaymentLeaf = { txHash: tx.hash, from: tx.from, to: tx.to ?? ethers.ZeroAddress, value: tx.value, blockNumber: block, blockTimestamp: Number(blk.timestamp), gasUsed: receipt?.gasUsed ?? 0n, success: receipt?.status === 1, logCount: meta.logCount, receiptHash: meta.receiptHash, }; const blockscoutApi = process.env.CHECKPOINT_BLOCKSCOUT_API || 'https://explorer.d-bis.org/api/v2'; const { allErc20 } = await enrichLeafFromBlockscoutApi(leaf, blockscoutApi, true); await enrichLeafUsd( leaf, { apiBaseUrl: process.env.CHECKPOINT_TOKEN_AGGREGATION_URL || process.env.TOKEN_AGGREGATION_API_URL || 'https://explorer.d-bis.org/api/v1', chainId: 138, enabled: process.env.CHECKPOINT_USD_ENRICH !== '0', requestDelayMs: 80, blockscoutApi, useBlockscout: true, }, allErc20 ); leaves.push(leaf); if (!dryRun) { console.log( 'leaf', tx.hash, 'wei', leaf.value.toString(), 'usdE8', usdStringToE8(leaf.totalTransfersUsd ?? leaf.valueUsd).toString() ); } } if (leaves.length === 0) { console.log('No transactions in block', block); return; } if (dryRun) { console.log( JSON.stringify( { dryRun: true, block, batchId: batchId.toString(), registry: registry || null, txCount: leaves.length, leaves: leaves.map((l) => ({ txHash: l.txHash, from: l.from, to: l.to, valueWei: l.value?.toString(), valueUsd: l.valueUsd, totalTransfersUsd: l.totalTransfersUsd, usdE8: usdStringToE8(l.totalTransfersUsd ?? l.valueUsd).toString(), })), }, null, 2 ) ); return; } const wallet = new ethers.Wallet(pk!, new ethers.JsonRpcProvider(rpc1)); attachIso20022ToLeaves(leaves); const activityTx = await recordActivityBatch(wallet, registry, batchId, leaves); console.log('AddressActivityRegistry tx', activityTx); const registryV2 = process.env.ADDRESS_ACTIVITY_REGISTRY_V2_MAINNET || ''; if (registryV2) { const isoTx = await recordIsoAttestationBatch(wallet, registryV2, batchId, leaves); console.log('AddressActivityRegistryV2 tx', isoTx); } if (dualMirror && mirror) { const mirrorTx = await dualWriteV1Mirror(wallet, mirror, leaves); console.log('TransactionMirror tx', mirrorTx); } } main().catch((e) => { console.error(e); process.exit(1); });