Files
smom-dbis-138/services/checkpoint-indexer/dist/etherscanV2Shim.js
defiQUG c336809676
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m3s
CI/CD Pipeline / Security Scanning (push) Successful in 2m18s
CI/CD Pipeline / Lint and Format (push) Failing after 34s
CI/CD Pipeline / Terraform Validation (push) Failing after 20s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 22s
Deploy ChainID 138 / Deploy ChainID 138 (push) Failing after 40s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 49s
OMNL reconcile anchor / Run omnl:reconcile and upload artifacts (push) Failing after 21s
Validation / validate-genesis (push) Successful in 25s
Validation / validate-terraform (push) Failing after 21s
Validation / validate-kubernetes (push) Failing after 8s
Validation / validate-smart-contracts (push) Failing after 8s
Validation / validate-security (push) Failing after 1m11s
Validation / validate-documentation (push) Failing after 14s
Verify Deployment / Verify Deployment (push) Failing after 45s
Add mainnet checkpoint stack: ISO attestation, participant Etherscan surface, and services.
Ship AddressActivityRegistry V1/V2, ISO20022IntakeGateway, Chain138ParticipantSurface,
checkpoint hub contracts, checkpoint-core package, aggregator/indexer/sdk services,
relay profile guards, M00 diamond bridge facet, and OMNL compliance contracts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-25 00:30:45 -07:00

313 lines
15 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.chainlistSupplement = chainlistSupplement;
exports.etherscanV2Api = etherscanV2Api;
const ethers_1 = require("ethers");
const config_1 = require("./config");
const addressIndex_1 = require("./addressIndex");
const chain138Explorer_1 = require("./chain138Explorer");
const iso20022LogDecode_1 = require("./iso20022LogDecode");
const participantSurfaceLogDecode_1 = require("./participantSurfaceLogDecode");
/** Etherscan V2-shaped envelope for tooling compatibility. */
function ok(result, message = 'OK') {
return { status: '1', message, result };
}
function err(message, result = null) {
return { status: '0', message, result };
}
function normalizeAddress(address) {
try {
return ethers_1.ethers.getAddress(address);
}
catch {
return ethers_1.ethers.getAddress(address.toLowerCase());
}
}
function padTopicAddress(address) {
return ethers_1.ethers.zeroPadValue(normalizeAddress(address), 32);
}
async function blockscoutTxList(address, page, offset) {
const base = config_1.checkpointIndexerConfig.blockscoutApi.replace(/\/$/, '');
const url = `${base}/addresses/${normalizeAddress(address)}/transactions?page=${page}&offset=${offset}`;
const res = await fetch(url);
if (!res.ok)
throw new Error(`blockscout ${res.status}`);
const body = (await res.json());
return (body.items ?? []).map((tx) => ({
blockNumber: String(tx.block_number ?? tx.blockNumber ?? ''),
timeStamp: tx.timestamp
? String(Math.floor(new Date(String(tx.timestamp)).getTime() / 1000))
: '',
hash: tx.hash,
from: tx.from?.hash ?? tx.from,
to: tx.to?.hash ?? tx.to,
value: String(tx.value ?? '0'),
gas: String(tx.fee?.gas_used ?? tx.gas_used ?? ''),
gasPrice: String(tx.gas_price ?? tx.gasPrice ?? '0'),
isError: tx.status === 'ok' || tx.status === 1 || tx.status === '0x1' ? '0' : '1',
txreceipt_status: tx.status === 'ok' || tx.status === 1 ? '1' : '0',
input: tx.raw_input ?? tx.input ?? '0x',
contractAddress: '',
cumulativeGasUsed: '',
confirmations: String(tx.confirmations ?? ''),
}));
}
async function etherscanV2GetLogs(params, apiKey) {
const q = new URLSearchParams(params);
q.set('chainid', '1');
q.set('module', 'logs');
q.set('action', 'getLogs');
if (apiKey)
q.set('apikey', apiKey);
const url = `https://api.etherscan.io/v2/api?${q.toString()}`;
const res = await fetch(url);
return res.json();
}
function chainlistSupplement(_req, res) {
const registry = config_1.checkpointIndexerConfig.addressActivityRegistry || null;
res.json({
comments: 'Supplemental chainlist for networks absent from official Etherscan V2 chainlist. Not maintained by Etherscan.',
totalcount: 2,
result: [
{
chainname: 'Defi Oracle Meta Mainnet',
chainid: '138',
blockexplorer: 'https://explorer.d-bis.org/',
apiurl: `${publicBase(_req)}/v2/api?chainid=138`,
status: 1,
comment: 'Blockscout native + project attestation shim',
},
{
chainname: 'Ethereum Mainnet (Chain 138 attestation layer)',
chainid: '1',
attestationLayer: true,
blockexplorer: 'https://etherscan.io/',
apiurl: `${publicBase(_req)}/v2/api?chainid=1&module=chain138mirror`,
status: 1,
comment: 'Query mirror/registry logs via chain138mirror module on this shim (not native Etherscan V2 module=account)',
contracts: {
transactionMirror: config_1.checkpointIndexerConfig.legacyMirror,
addressActivityRegistry: registry,
addressActivityRegistryV2: config_1.checkpointIndexerConfig.addressActivityRegistryV2 || null,
iso20022IntakeGateway: config_1.checkpointIndexerConfig.iso20022IntakeGateway || null,
checkpointHub: config_1.checkpointIndexerConfig.checkpointProxy || null,
},
},
],
});
}
function publicBase(req) {
const proto = req.headers['x-forwarded-proto'] || req.protocol;
const host = req.headers['x-forwarded-host'] || req.headers.host || `127.0.0.1:${config_1.checkpointIndexerConfig.port}`;
return `${proto}://${host}`;
}
async function etherscanV2Api(req, res) {
const q = req.query;
const chainid = String(q.chainid ?? '');
const module = String(q.module ?? '');
const action = String(q.action ?? '');
const apiKey = String(q.apikey ?? process.env.ETHERSCAN_API_KEY ?? '');
if (!chainid) {
return res.json(err('Missing or unsupported chainid parameter (required for v2 api), please see chainlist-supplement for Chain 138'));
}
try {
if (chainid === '138') {
return res.json(await handleChain138(module, action, q));
}
if (chainid === '1' && module === 'chain138mirror') {
return res.json(await handleMainnetAttestation(action, q, apiKey));
}
if (chainid === '1' && module === 'proxy') {
return res.json(err('Use official https://api.etherscan.io/v2/api for chainid=1 proxy module'));
}
return res.json(err(`Chain ${chainid} is not served by this shim. Chain 138 native: chainid=138. Chain 138 on mainnet attestation: chainid=1&module=chain138mirror`));
}
catch (e) {
return res.json(err(String(e)));
}
}
async function handleChain138(module, action, q) {
const address = String(q.address ?? '');
if (module === 'account' && action === 'balance') {
if (!/^0x[a-fA-F0-9]{40}$/.test(address))
return err('Invalid address');
const provider = new ethers_1.ethers.JsonRpcProvider(config_1.checkpointIndexerConfig.chain138Rpc);
const bal = await provider.getBalance(normalizeAddress(address));
return ok(bal.toString());
}
if (module === 'account' && action === 'txlist') {
if (!/^0x[a-fA-F0-9]{40}$/.test(address))
return err('Invalid address');
const page = parseInt(String(q.page ?? '1'), 10) || 1;
const offset = Math.min(parseInt(String(q.offset ?? '10'), 10) || 10, 100);
const items = await blockscoutTxList(normalizeAddress(address), page, offset);
return ok(items);
}
if (module === 'chain138' && action === 'attestation') {
const txHash = String(q.txhash ?? q.txHash ?? '');
if (!/^0x[a-fA-F0-9]{64}$/.test(txHash))
return err('Invalid txhash');
const base = publicBaseFromQuery(q);
const r = await fetch(`${base}/v1/tx/${txHash}/attestation`);
if (!r.ok)
return err('attestation not found');
return ok(await r.json());
}
if (module === 'chain138' && action === 'participantactivity') {
if (!/^0x[a-fA-F0-9]{40}$/.test(address))
return err('Invalid address');
const normalized = normalizeAddress(address);
const index = (0, addressIndex_1.buildAddressIndex)(config_1.checkpointIndexerConfig.batchPayloadDir);
const { total, items } = (0, addressIndex_1.getAddressTransactions)(index, normalized, Math.min(parseInt(String(q.offset ?? '50'), 10) || 50, 200), parseInt(String(q.page ?? '0'), 10) || 0);
const summary = (0, addressIndex_1.summarizeAddressActivity)(index.byAddress[normalized.toLowerCase()] ?? []);
const onChainHint = total === 0 && config_1.checkpointIndexerConfig.addressActivityRegistry
? {
registry: config_1.checkpointIndexerConfig.addressActivityRegistry,
query: 'GET /v2/api?chainid=1&module=chain138mirror&action=participantlogs&address=' +
normalized,
}
: null;
return ok({ total, summary, items, onChainHint });
}
if (module === 'proxy' && action === 'eth_blockNumber') {
const provider = new ethers_1.ethers.JsonRpcProvider(config_1.checkpointIndexerConfig.chain138Rpc);
const block = await provider.getBlockNumber();
return ok(`0x${block.toString(16)}`);
}
return err(`Unsupported module/action for chainid=138: ${module}/${action}`);
}
function publicBaseFromQuery(q) {
const override = String(q.indexerBase ?? process.env.CHECKPOINT_PAYLOAD_PUBLIC_URL ?? '');
if (override.startsWith('http'))
return override.replace(/\/v1\/payload\/?$/, '').replace(/\/$/, '');
return `http://127.0.0.1:${config_1.checkpointIndexerConfig.port}`;
}
async function handleMainnetAttestation(action, q, apiKey) {
const registry = config_1.checkpointIndexerConfig.addressActivityRegistry;
const mirror = config_1.checkpointIndexerConfig.legacyMirror;
const address = String(q.address ?? '');
if (action === 'contracts') {
const explorerBase = (0, chain138Explorer_1.chain138ExplorerBase)();
return ok({
transactionMirror: mirror,
addressActivityRegistry: registry || null,
checkpointHub: config_1.checkpointIndexerConfig.checkpointProxy || null,
chain138Explorer: {
base: explorerBase,
txUrlTemplate: `${explorerBase}/tx/{txHash}`,
},
eventTopics: {
TransactionMirrored: '0xc25ce5062c7e42c68fa21fe088d21e609cc0c61b8bec3180681363bb5cf02a9e',
ParticipantCredited: '0x853ebad0824f583553bcb4360a0df947d39654e86aba8d7c0625499cbf09f0d5',
ParticipantDebited: '0xf122cad7c8ada37ddd6b6ddca0982b9f7be689cde15eedfd767cc207fa7dc2c8',
},
});
}
if (action === 'participantlogs') {
if (!registry && !config_1.checkpointIndexerConfig.addressActivityRegistryV2) {
return err('ADDRESS_ACTIVITY_REGISTRY_MAINNET or V2 not configured');
}
if (!/^0x[a-fA-F0-9]{40}$/.test(address))
return err('Invalid address');
if (!apiKey)
return err('ETHERSCAN_API_KEY required for mainnet log proxy');
const topic = padTopicAddress(address);
const params = new URLSearchParams({
fromBlock: String(q.fromBlock ?? '0'),
toBlock: String(q.toBlock ?? 'latest'),
});
let credited = { status: '0', message: 'No records', result: [] };
let debited = { status: '0', message: 'No records', result: [] };
if (registry) {
const regParams = new URLSearchParams([...params.entries(), ['address', registry]]);
credited = await etherscanV2GetLogs(new URLSearchParams([
...regParams.entries(),
['topic0', '0x853ebad0824f583553bcb4360a0df947d39654e86aba8d7c0625499cbf09f0d5'],
['topic2', topic],
]), apiKey);
debited = await etherscanV2GetLogs(new URLSearchParams([
...regParams.entries(),
['topic0', '0xf122cad7c8ada37ddd6b6ddca0982b9f7be689cde15eedfd767cc207fa7dc2c8'],
['topic3', topic],
]), apiKey);
}
let surfaceNotify = null;
if (config_1.checkpointIndexerConfig.participantSurface) {
const surfaceRaw = await etherscanV2GetLogs(new URLSearchParams([
...params.entries(),
['address', config_1.checkpointIndexerConfig.participantSurface],
['topic0', participantSurfaceLogDecode_1.CHAIN138_ACTIVITY_NOTIFIED_TOPIC0],
['topic1', topic],
]), apiKey);
const surfaceEnv = surfaceRaw;
surfaceNotify = {
status: surfaceEnv.status,
result: surfaceEnv.result ?? [],
decoded: (0, participantSurfaceLogDecode_1.decodeChain138ActivityNotifiedLogs)(surfaceEnv, (0, chain138Explorer_1.chain138ExplorerBase)()),
};
}
let isoV2 = null;
if (config_1.checkpointIndexerConfig.addressActivityRegistryV2) {
const v2raw = await etherscanV2GetLogs(new URLSearchParams([
...params.entries(),
['address', config_1.checkpointIndexerConfig.addressActivityRegistryV2],
['topic0', iso20022LogDecode_1.PAYMENT_ATTESTED_TOPIC0],
['topic3', topic],
]), apiKey);
const v2env = v2raw;
isoV2 = {
status: v2env.status,
result: v2env.result ?? [],
decoded: (0, iso20022LogDecode_1.decodePaymentAttestedLogs)(v2env, (0, chain138Explorer_1.chain138ExplorerBase)()),
};
}
return ok({
participant: normalizeAddress(address),
registry: registry || null,
registryV2: config_1.checkpointIndexerConfig.addressActivityRegistryV2 || null,
participantSurface: config_1.checkpointIndexerConfig.participantSurface || null,
credited: (0, chain138Explorer_1.enrichRegistryLogsEnvelope)(credited),
debited: (0, chain138Explorer_1.enrichRegistryLogsEnvelope)(debited),
surfaceNotifications: surfaceNotify,
iso20022V2: isoV2,
chain138Explorer: {
base: (0, chain138Explorer_1.chain138ExplorerBase)(),
txUrlTemplate: `${(0, chain138Explorer_1.chain138ExplorerBase)()}/tx/{txHash}`,
},
topicIndex: {
ParticipantCredited: { chain138TxHash: 'topic1', participant: 'topic2', counterparty: 'topic3' },
ParticipantDebited: { chain138TxHash: 'topic1', counterparty: 'topic2', participant: 'topic3' },
PaymentAttested: { chain138TxHash: 'topic1', instructionId: 'topic2', creditor: 'topic3' },
Chain138ActivityNotified: {
participant: 'topic1',
chain138TxHash: 'topic2',
instructionId: 'topic3',
},
},
etherscanVisibility: {
transactionsTab: 'Set CHECKPOINT_SURFACE_TOPLEVEL_ZERO_ETH=1 on aggregator for incoming 0 ETH txs to participant',
internalTxnsTab: 'Chain138ParticipantSurface wallet touch (walletTouchEnabled)',
eventsOnSurfaceContract: 'surfaceNotifications.decoded[] with chain138ExplorerUrl',
},
note: 'credited/debited.decoded[], surfaceNotifications.decoded[], and iso20022V2.decoded[] include chain138ExplorerUrl. Full pacs.008 XML in batch payloads and config/iso20022-omnl/messages.',
});
}
if (action === 'mirrorlogs') {
if (!/^0x[a-fA-F0-9]{64}$/.test(String(q.txhash ?? '')))
return err('Invalid txhash');
if (!apiKey)
return err('ETHERSCAN_API_KEY required');
const txHash = String(q.txhash);
const params = new URLSearchParams({
address: mirror,
fromBlock: String(q.fromBlock ?? '0'),
toBlock: String(q.toBlock ?? 'latest'),
topic0: '0xc25ce5062c7e42c68fa21fe088d21e609cc0c61b8bec3180681363bb5cf02a9e',
topic1: txHash,
});
const logs = await etherscanV2GetLogs(params, apiKey);
return ok(logs);
}
return err(`Unsupported chain138mirror action: ${action}`);
}