Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m12s
CI/CD Pipeline / Security Scanning (push) Successful in 2m38s
CI/CD Pipeline / Lint and Format (push) Failing after 40s
CI/CD Pipeline / Terraform Validation (push) Failing after 21s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 24s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 24s
Validation / validate-genesis (push) Successful in 26s
Validation / validate-terraform (push) Failing after 21s
Validation / validate-kubernetes (push) Failing after 9s
Validation / validate-smart-contracts (push) Failing after 9s
Validation / validate-security (push) Failing after 1m7s
Validation / validate-documentation (push) Failing after 15s
Resolve etherscanLinks from batch metadata and optional mainnet log scans; serve a fast local-batch attestation path for the explorer CT. Co-authored-by: Cursor <cursoragent@cursor.com>
145 lines
5.6 KiB
JavaScript
145 lines
5.6 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.CHAIN138_ATTESTATION_IFACE = exports.DIRECTION_DEBITED = exports.DIRECTION_CREDITED = void 0;
|
|
exports.buildTopLevelSurfaceTargets = buildTopLevelSurfaceTargets;
|
|
exports.surfaceParticipantsOnMainnet = surfaceParticipantsOnMainnet;
|
|
exports.surfaceTopLevelZeroEth = surfaceTopLevelZeroEth;
|
|
const ethers_1 = require("ethers");
|
|
const checkpoint_core_1 = require("@dbis/checkpoint-core");
|
|
const leafCodec_1 = require("./leafCodec");
|
|
const SURFACE_ABI = [
|
|
'function notifyBatch(uint64 batchId, tuple(address participant,bytes32 chain138TxHash,bytes32 instructionId,uint8 direction,uint64 batchId,uint256 valueWei,uint64 valueUsdE8)[] items) external',
|
|
'function notified(bytes32) view returns (bool)',
|
|
'function notificationKey(address participant, bytes32 chain138TxHash, uint8 direction) view returns (bytes32)',
|
|
];
|
|
exports.DIRECTION_CREDITED = 0;
|
|
exports.DIRECTION_DEBITED = 1;
|
|
/** Matches Chain138ParticipantSurface wallet touch + top-level relayer calldata. */
|
|
exports.CHAIN138_ATTESTATION_IFACE = new ethers_1.ethers.Interface([
|
|
'function chain138Attestation(bytes32 chain138TxHash, uint8 direction, uint64 batchId)',
|
|
]);
|
|
/** One top-level mainnet tx per (participant, chain138TxHash, direction) — both wallets per 138 payment. */
|
|
function buildTopLevelSurfaceTargets(leaves, batchId) {
|
|
const seen = new Set();
|
|
const out = [];
|
|
for (const leaf of leaves) {
|
|
const pairs = [
|
|
{ participant: leaf.from, direction: exports.DIRECTION_DEBITED },
|
|
{ participant: leaf.to, direction: exports.DIRECTION_CREDITED },
|
|
];
|
|
for (const { participant, direction } of pairs) {
|
|
if (!participant || participant === ethers_1.ethers.ZeroAddress)
|
|
continue;
|
|
const key = `${participant.toLowerCase()}:${leaf.txHash}:${direction}`;
|
|
if (seen.has(key))
|
|
continue;
|
|
seen.add(key);
|
|
out.push({
|
|
participant,
|
|
chain138TxHash: leaf.txHash,
|
|
direction,
|
|
batchId,
|
|
blockNumber: leaf.blockNumber,
|
|
});
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
function buildNotifications(leaves, batchId) {
|
|
const items = [];
|
|
for (const leaf of leaves) {
|
|
const iso = leaf.iso20022 ?? (0, checkpoint_core_1.mapPaymentLeafToCanonical)(leaf);
|
|
const usd = leaf.totalTransfersUsd ?? leaf.valueUsd ?? leaf.nativeValueUsd ?? '0';
|
|
const valueWei = (0, leafCodec_1.effectiveValue)(leaf);
|
|
const valueUsdE8 = (0, checkpoint_core_1.usdStringToE8)(usd);
|
|
items.push({
|
|
participant: leaf.from,
|
|
chain138TxHash: leaf.txHash,
|
|
instructionId: iso.instructionIdBytes32,
|
|
direction: exports.DIRECTION_DEBITED,
|
|
batchId,
|
|
valueWei,
|
|
valueUsdE8,
|
|
});
|
|
items.push({
|
|
participant: leaf.to,
|
|
chain138TxHash: leaf.txHash,
|
|
instructionId: iso.instructionIdBytes32,
|
|
direction: exports.DIRECTION_CREDITED,
|
|
batchId,
|
|
valueWei,
|
|
valueUsdE8,
|
|
});
|
|
}
|
|
return items;
|
|
}
|
|
async function surfaceParticipantsOnMainnet(wallet, surfaceAddress, batchId, leaves) {
|
|
if (!surfaceAddress || leaves.length === 0)
|
|
return null;
|
|
const surface = new ethers_1.ethers.Contract(surfaceAddress, SURFACE_ABI, wallet);
|
|
const all = buildNotifications(leaves, batchId);
|
|
const pending = [];
|
|
for (const item of all) {
|
|
const key = await surface.notificationKey(item.participant, item.chain138TxHash, item.direction);
|
|
try {
|
|
if (await surface.notified(key))
|
|
continue;
|
|
}
|
|
catch {
|
|
/* continue */
|
|
}
|
|
pending.push(item);
|
|
}
|
|
if (pending.length === 0)
|
|
return null;
|
|
const tx = await surface.notifyBatch(batchId, pending.map((p) => ({
|
|
participant: p.participant,
|
|
chain138TxHash: p.chain138TxHash,
|
|
instructionId: p.instructionId,
|
|
direction: p.direction,
|
|
batchId: p.batchId,
|
|
valueWei: p.valueWei,
|
|
valueUsdE8: p.valueUsdE8,
|
|
})), { gasLimit: 5000000n });
|
|
await tx.wait();
|
|
return tx.hash;
|
|
}
|
|
/**
|
|
* One top-level 0 ETH tx TO each participant role (sender + receiver per Chain 138 tx).
|
|
* Shows on each wallet's Etherscan **Transactions** tab; calldata carries chain138TxHash.
|
|
*/
|
|
async function surfaceTopLevelZeroEth(wallet, leaves, batchId) {
|
|
const targets = buildTopLevelSurfaceTargets(leaves, batchId);
|
|
let count = 0;
|
|
for (const item of targets) {
|
|
const code = await wallet.provider.getCode(item.participant);
|
|
if (code !== '0x') {
|
|
console.warn(` skip top-level surface for contract wallet ${item.participant} (use Internal Txns / surface events)`);
|
|
continue;
|
|
}
|
|
const data = exports.CHAIN138_ATTESTATION_IFACE.encodeFunctionData('chain138Attestation', [
|
|
item.chain138TxHash,
|
|
item.direction,
|
|
item.batchId,
|
|
]);
|
|
try {
|
|
const tx = await wallet.sendTransaction({
|
|
to: item.participant,
|
|
value: 0n,
|
|
data,
|
|
gasLimit: 55000n,
|
|
});
|
|
const receipt = await tx.wait();
|
|
if (receipt?.status !== 1) {
|
|
console.warn(` top-level surface reverted for ${item.participant} tx=${tx.hash}`);
|
|
continue;
|
|
}
|
|
count++;
|
|
}
|
|
catch (e) {
|
|
console.warn(` top-level surface failed for ${item.participant}`, e);
|
|
}
|
|
}
|
|
return count;
|
|
}
|