2026-02-12 15:46:57 -08:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
/**
|
|
|
|
|
* Forge Verification Proxy — bridges Forge to Blockscout
|
|
|
|
|
*
|
|
|
|
|
* Strategy 1: Forward to Etherscan-compatible API with module/action in query
|
|
|
|
|
* Strategy 2 (fallback): Forward to Blockscout v2 API
|
|
|
|
|
*
|
|
|
|
|
* Forge sends: POST with JSON { contractaddress, sourceCode, codeformat, ... }
|
|
|
|
|
* Blockscout Etherscan API expects: ?module=contract&action=verifysourcecode (in URL)
|
|
|
|
|
*
|
|
|
|
|
* Usage: BLOCKSCOUT_URL=http://192.168.11.140:4000 node server.js
|
|
|
|
|
* Forge: --verifier-url "http://localhost:3080/"
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import http from 'node:http';
|
|
|
|
|
|
|
|
|
|
const PORT = parseInt(process.env.PORT || '3080', 10);
|
|
|
|
|
const BLOCKSCOUT_URL = (process.env.BLOCKSCOUT_URL || 'http://192.168.11.140:4000').replace(/\/$/, '');
|
|
|
|
|
|
2026-02-21 15:46:06 -08:00
|
|
|
/** Parse body as JSON or application/x-www-form-urlencoded (Forge/Etherscan style). */
|
|
|
|
|
function parseBody(req) {
|
2026-02-12 15:46:57 -08:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
let body = '';
|
|
|
|
|
req.on('data', (chunk) => { body += chunk; });
|
|
|
|
|
req.on('end', () => {
|
2026-02-21 15:46:06 -08:00
|
|
|
if (!body || !body.trim()) {
|
|
|
|
|
resolve({});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const contentType = (req.headers['content-type'] || '').toLowerCase();
|
|
|
|
|
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
|
|
|
try {
|
|
|
|
|
const params = new URLSearchParams(body);
|
|
|
|
|
const payload = {};
|
|
|
|
|
for (const [k, v] of params) {
|
|
|
|
|
if (v !== undefined && v !== '') payload[k] = v;
|
|
|
|
|
}
|
|
|
|
|
resolve(payload);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
reject(e);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-02-12 15:46:57 -08:00
|
|
|
try {
|
2026-02-21 15:46:06 -08:00
|
|
|
resolve(JSON.parse(body));
|
2026-02-12 15:46:57 -08:00
|
|
|
} catch (e) {
|
|
|
|
|
reject(e);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
req.on('error', reject);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function send(res, status, data) {
|
|
|
|
|
res.writeHead(status, { 'Content-Type': 'application/json' });
|
|
|
|
|
res.end(JSON.stringify(data));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Forward to Blockscout Etherscan API with module/action in query.
|
|
|
|
|
* Same JSON body, but URL includes required params.
|
|
|
|
|
*/
|
|
|
|
|
async function forwardEtherscanFormat(payload) {
|
|
|
|
|
const query = new URLSearchParams({ module: 'contract', action: 'verifysourcecode' });
|
|
|
|
|
const path = `/api/?${query}`;
|
feat(omnl): HYBX-BATCH-001 package, rail scripts, regulatory docs, CI
- Add OMNL/CBK Indonesia submission and audit binder docs, manifests, attestations
- Add scripts/omnl transaction-package pipeline, LEI/PvP helpers, jq/lib fixtures
- Update entity master data, MASTER_INDEX, TODOS, dbis-rail docs and rulebook
- Add proof_package/regulatory skeleton and transaction package zip + snapshot JSON
- validate-omnl-rail workflow, forge-verification-proxy tweak, .gitignore hygiene
- Bump smom-dbis-138 (cronos verify docs/scripts) and explorer-monorepo (SPA + env report)
Made-with: Cursor
2026-03-24 18:11:36 -07:00
|
|
|
// Blockscout's Etherscan-compatible endpoint expects classic form fields, not JSON.
|
|
|
|
|
// Keep the Forge payload keys, but serialize them as application/x-www-form-urlencoded.
|
|
|
|
|
const form = new URLSearchParams();
|
|
|
|
|
for (const [key, value] of Object.entries(payload)) {
|
|
|
|
|
if (value === undefined || value === null || value === '') continue;
|
|
|
|
|
form.set(key, String(value));
|
|
|
|
|
}
|
|
|
|
|
const body = form.toString();
|
2026-02-12 15:46:57 -08:00
|
|
|
const url = new URL(path, BLOCKSCOUT_URL);
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const req = http.request(
|
|
|
|
|
{
|
|
|
|
|
hostname: url.hostname,
|
|
|
|
|
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
|
|
|
path: url.pathname + url.search,
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
feat(omnl): HYBX-BATCH-001 package, rail scripts, regulatory docs, CI
- Add OMNL/CBK Indonesia submission and audit binder docs, manifests, attestations
- Add scripts/omnl transaction-package pipeline, LEI/PvP helpers, jq/lib fixtures
- Update entity master data, MASTER_INDEX, TODOS, dbis-rail docs and rulebook
- Add proof_package/regulatory skeleton and transaction package zip + snapshot JSON
- validate-omnl-rail workflow, forge-verification-proxy tweak, .gitignore hygiene
- Bump smom-dbis-138 (cronos verify docs/scripts) and explorer-monorepo (SPA + env report)
Made-with: Cursor
2026-03-24 18:11:36 -07:00
|
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
2026-02-12 15:46:57 -08:00
|
|
|
'Content-Length': Buffer.byteLength(body),
|
|
|
|
|
Host: url.hostname + (url.port ? ':' + url.port : ''),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
(res) => {
|
|
|
|
|
let data = '';
|
|
|
|
|
res.on('data', (chunk) => { data += chunk; });
|
|
|
|
|
res.on('end', () => {
|
|
|
|
|
try {
|
|
|
|
|
resolve({ status: res.statusCode, data: data ? JSON.parse(data) : {}, raw: data });
|
|
|
|
|
} catch {
|
|
|
|
|
resolve({ status: res.statusCode, data: null, raw: data });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
req.on('error', reject);
|
|
|
|
|
req.write(body);
|
|
|
|
|
req.end();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
feat(omnl): HYBX-BATCH-001 package, rail scripts, regulatory docs, CI
- Add OMNL/CBK Indonesia submission and audit binder docs, manifests, attestations
- Add scripts/omnl transaction-package pipeline, LEI/PvP helpers, jq/lib fixtures
- Update entity master data, MASTER_INDEX, TODOS, dbis-rail docs and rulebook
- Add proof_package/regulatory skeleton and transaction package zip + snapshot JSON
- validate-omnl-rail workflow, forge-verification-proxy tweak, .gitignore hygiene
- Bump smom-dbis-138 (cronos verify docs/scripts) and explorer-monorepo (SPA + env report)
Made-with: Cursor
2026-03-24 18:11:36 -07:00
|
|
|
* Forward to Blockscout v2 flattened-code verification API.
|
2026-02-12 15:46:57 -08:00
|
|
|
*/
|
|
|
|
|
async function forwardV2Flattened(payload) {
|
|
|
|
|
const addr = payload.contractaddress || payload.contractAddress;
|
|
|
|
|
const sourceCode = payload.sourceCode ?? payload.source_code;
|
|
|
|
|
const codeformat = (payload.codeformat || '').toLowerCase();
|
|
|
|
|
const isStandardJson =
|
|
|
|
|
codeformat === 'solidity-standard-json-input' ||
|
|
|
|
|
(typeof sourceCode === 'string' && sourceCode.trimStart().startsWith('{') && sourceCode.includes('"sources"'));
|
|
|
|
|
|
|
|
|
|
const path = isStandardJson
|
|
|
|
|
? `/api/v2/smart-contracts/${addr}/verification/via/standard-input`
|
|
|
|
|
: `/api/v2/smart-contracts/${addr}/verification/via/flattened-code`;
|
|
|
|
|
|
|
|
|
|
const v2Body = {
|
|
|
|
|
compiler_version: payload.compilerversion || payload.compilerVersion || 'v0.8.20+commit.a1b79de6',
|
|
|
|
|
contract_name: payload.contractname || payload.contractName || 'Contract',
|
|
|
|
|
license_type: payload.licensetype || payload.licenseType || 'mit',
|
|
|
|
|
is_optimization_enabled: [true, '1', 1, 'true'].includes(payload.optimizationUsed ?? payload.optimization_used),
|
|
|
|
|
optimization_runs: parseInt(payload.runs ?? payload.optimization_runs ?? '200', 10) || 200,
|
|
|
|
|
evm_version: payload.evmversion || payload.evm_version || 'london',
|
|
|
|
|
autodetect_constructor_args: payload.autodetectConstructorArguments !== false,
|
|
|
|
|
source_code: typeof sourceCode === 'string' ? sourceCode : JSON.stringify(sourceCode),
|
|
|
|
|
};
|
|
|
|
|
if (payload.constructorArguments) v2Body.constructor_args = payload.constructorArguments;
|
|
|
|
|
|
|
|
|
|
const body = JSON.stringify(v2Body);
|
|
|
|
|
const url = new URL(path, BLOCKSCOUT_URL);
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const req = http.request(
|
|
|
|
|
{
|
|
|
|
|
hostname: url.hostname,
|
|
|
|
|
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
|
|
|
path: url.pathname,
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': 'application/json',
|
|
|
|
|
'Content-Length': Buffer.byteLength(body),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
(res) => {
|
|
|
|
|
let data = '';
|
|
|
|
|
res.on('data', (chunk) => { data += chunk; });
|
|
|
|
|
res.on('end', () => {
|
|
|
|
|
try {
|
|
|
|
|
resolve({ status: res.statusCode, data: data ? JSON.parse(data) : {}, raw: data });
|
|
|
|
|
} catch {
|
|
|
|
|
resolve({ status: res.statusCode, data: null, raw: data });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
req.on('error', reject);
|
|
|
|
|
req.write(body);
|
|
|
|
|
req.end();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
feat(omnl): HYBX-BATCH-001 package, rail scripts, regulatory docs, CI
- Add OMNL/CBK Indonesia submission and audit binder docs, manifests, attestations
- Add scripts/omnl transaction-package pipeline, LEI/PvP helpers, jq/lib fixtures
- Update entity master data, MASTER_INDEX, TODOS, dbis-rail docs and rulebook
- Add proof_package/regulatory skeleton and transaction package zip + snapshot JSON
- validate-omnl-rail workflow, forge-verification-proxy tweak, .gitignore hygiene
- Bump smom-dbis-138 (cronos verify docs/scripts) and explorer-monorepo (SPA + env report)
Made-with: Cursor
2026-03-24 18:11:36 -07:00
|
|
|
/**
|
|
|
|
|
* Forward to Blockscout v2 verification API for Standard JSON input.
|
|
|
|
|
*/
|
|
|
|
|
async function forwardV2StandardInput(payload) {
|
|
|
|
|
const addr = payload.contractaddress || payload.contractAddress;
|
|
|
|
|
const sourceCode = payload.sourceCode ?? payload.source_code;
|
|
|
|
|
const standardJson =
|
|
|
|
|
typeof sourceCode === 'string'
|
|
|
|
|
? sourceCode
|
|
|
|
|
: JSON.stringify(sourceCode);
|
|
|
|
|
const path = `/api/v2/smart-contracts/${addr}/verification/via/standard-input`;
|
|
|
|
|
const boundary = `----forge-verification-proxy-${Math.random().toString(16).slice(2)}`;
|
|
|
|
|
const parts = [];
|
|
|
|
|
const appendField = (name, value) => {
|
|
|
|
|
if (value === undefined || value === null || value === '') return;
|
|
|
|
|
parts.push(Buffer.from(`--${boundary}\r\n`));
|
|
|
|
|
parts.push(Buffer.from(`Content-Disposition: form-data; name="${name}"\r\n\r\n`));
|
|
|
|
|
parts.push(Buffer.from(`${value}\r\n`));
|
|
|
|
|
};
|
|
|
|
|
const appendFile = (name, filename, content, contentType = 'application/json') => {
|
|
|
|
|
parts.push(Buffer.from(`--${boundary}\r\n`));
|
|
|
|
|
parts.push(Buffer.from(`Content-Disposition: form-data; name="${name}"; filename="${filename}"\r\n`));
|
|
|
|
|
parts.push(Buffer.from(`Content-Type: ${contentType}\r\n\r\n`));
|
|
|
|
|
parts.push(Buffer.isBuffer(content) ? content : Buffer.from(String(content)));
|
|
|
|
|
parts.push(Buffer.from('\r\n'));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const compilerVersion = payload.compilerversion || payload.compilerVersion || 'v0.8.20+commit.a1b79de6';
|
|
|
|
|
const contractName = payload.contractname || payload.contractName || 'Contract';
|
|
|
|
|
const licenseType = payload.licensetype || payload.licenseType || 'mit';
|
|
|
|
|
const constructorArgs =
|
|
|
|
|
payload.constructor_args ??
|
|
|
|
|
payload.constructorArguments ??
|
|
|
|
|
payload.constructorArgumentsHex ??
|
|
|
|
|
payload.constructorArgs ??
|
|
|
|
|
'';
|
|
|
|
|
|
|
|
|
|
appendField('compiler_version', compilerVersion);
|
|
|
|
|
appendField('contract_name', contractName);
|
|
|
|
|
appendField('autodetect_constructor_args', String(payload.autodetectConstructorArguments !== false));
|
|
|
|
|
appendField('license_type', licenseType);
|
|
|
|
|
appendField('constructor_args', constructorArgs);
|
|
|
|
|
if (payload.evmversion || payload.evm_version) appendField('evm_version', payload.evmversion || payload.evm_version);
|
|
|
|
|
if (payload.optimizationUsed !== undefined || payload.optimization_used !== undefined) {
|
|
|
|
|
appendField('is_optimization_enabled', String([true, '1', 1, 'true'].includes(payload.optimizationUsed ?? payload.optimization_used)));
|
|
|
|
|
}
|
|
|
|
|
if (payload.runs !== undefined || payload.optimization_runs !== undefined) {
|
|
|
|
|
appendField('optimization_runs', String(parseInt(payload.runs ?? payload.optimization_runs ?? '200', 10) || 200));
|
|
|
|
|
}
|
|
|
|
|
appendFile('files[0]', 'standard-input.json', standardJson, 'application/json');
|
|
|
|
|
parts.push(Buffer.from(`--${boundary}--\r\n`));
|
|
|
|
|
const body = Buffer.concat(parts);
|
|
|
|
|
const url = new URL(path, BLOCKSCOUT_URL);
|
|
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const req = http.request(
|
|
|
|
|
{
|
|
|
|
|
hostname: url.hostname,
|
|
|
|
|
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
|
|
|
path: url.pathname,
|
|
|
|
|
method: 'POST',
|
|
|
|
|
headers: {
|
|
|
|
|
'Content-Type': `multipart/form-data; boundary=${boundary}`,
|
|
|
|
|
'Content-Length': body.length,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
(res) => {
|
|
|
|
|
let data = '';
|
|
|
|
|
res.on('data', (chunk) => { data += chunk; });
|
|
|
|
|
res.on('end', () => {
|
|
|
|
|
try {
|
|
|
|
|
resolve({ status: res.statusCode, data: data ? JSON.parse(data) : {}, raw: data });
|
|
|
|
|
} catch {
|
|
|
|
|
resolve({ status: res.statusCode, data: null, raw: data });
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
req.on('error', reject);
|
|
|
|
|
req.write(body);
|
|
|
|
|
req.end();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-12 15:46:57 -08:00
|
|
|
function toEtherscanResponse(result) {
|
|
|
|
|
const { status, data, raw } = result;
|
|
|
|
|
if (status >= 200 && status < 300 && data?.status === '1') {
|
|
|
|
|
return { status: '1', message: data.message || 'OK', result: data.result ?? 'Verification submitted' };
|
|
|
|
|
}
|
|
|
|
|
if (status >= 200 && status < 300) {
|
|
|
|
|
return { status: '1', message: 'OK', result: data?.result ?? 'Verification submitted' };
|
|
|
|
|
}
|
|
|
|
|
// Blockscout may return HTML (502/500) or invalid JSON when DB/migrations fail
|
|
|
|
|
let msg = data?.message || data?.error;
|
|
|
|
|
if (!msg && raw) {
|
|
|
|
|
if (raw.trimStart().startsWith('<')) {
|
|
|
|
|
msg = 'Blockscout returned HTML (likely DB down or migrations needed). Run scripts/fix-blockscout-ssl-and-migrations.sh';
|
|
|
|
|
} else if (raw.length > 200) {
|
|
|
|
|
msg = raw.slice(0, 200) + '...';
|
|
|
|
|
} else {
|
|
|
|
|
msg = raw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
status: '0',
|
|
|
|
|
message: msg || 'Verification failed',
|
|
|
|
|
result: null,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Forward GET/other requests to Blockscout (getabi, checkverifystatus, etc.) */
|
|
|
|
|
function proxyToBlockscout(req, res) {
|
|
|
|
|
let targetPath = (req.url || '/').startsWith('/api') ? req.url : '/api' + (req.url === '/' ? '' : req.url);
|
|
|
|
|
// Blockscout redirects /api to /api/ — use /api/ to avoid 301
|
|
|
|
|
if (targetPath.startsWith('/api?') || targetPath === '/api') {
|
|
|
|
|
targetPath = '/api/' + (targetPath.slice(4) || '');
|
|
|
|
|
}
|
|
|
|
|
const url = new URL(targetPath, BLOCKSCOUT_URL);
|
|
|
|
|
|
|
|
|
|
const proxyReq = http.request(
|
|
|
|
|
{
|
|
|
|
|
hostname: url.hostname,
|
|
|
|
|
port: url.port || (url.protocol === 'https:' ? 443 : 80),
|
|
|
|
|
path: url.pathname + url.search,
|
|
|
|
|
method: req.method,
|
|
|
|
|
headers: { host: url.host },
|
|
|
|
|
},
|
|
|
|
|
(proxyRes) => {
|
|
|
|
|
const headers = { ...proxyRes.headers };
|
|
|
|
|
delete headers['transfer-encoding'];
|
|
|
|
|
res.writeHead(proxyRes.statusCode || 200, headers);
|
|
|
|
|
proxyRes.pipe(res);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
proxyReq.on('error', (e) => {
|
|
|
|
|
console.error('[forge-verification-proxy]', e.message);
|
|
|
|
|
send(res, 502, { status: '0', message: 'Blockscout unreachable', result: null });
|
|
|
|
|
});
|
|
|
|
|
if (req.method === 'POST' || req.method === 'PUT') {
|
|
|
|
|
req.pipe(proxyReq);
|
|
|
|
|
} else {
|
|
|
|
|
proxyReq.end();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const server = http.createServer(async (req, res) => {
|
|
|
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
|
|
|
if (req.method === 'OPTIONS') {
|
|
|
|
|
res.writeHead(204);
|
|
|
|
|
res.end();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const path = (req.url || '/').split('?')[0];
|
|
|
|
|
|
|
|
|
|
if (req.method === 'GET') {
|
|
|
|
|
await proxyToBlockscout(req, res);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (req.method !== 'POST') {
|
|
|
|
|
send(res, 405, { status: '0', message: 'Method not allowed', result: null });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let payload;
|
|
|
|
|
try {
|
2026-02-21 15:46:06 -08:00
|
|
|
payload = await parseBody(req);
|
2026-02-12 15:46:57 -08:00
|
|
|
} catch (e) {
|
2026-02-21 15:46:06 -08:00
|
|
|
send(res, 400, { status: '0', message: 'Invalid request body (JSON or form)', result: null });
|
2026-02-12 15:46:57 -08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!payload.contractaddress && !payload.contractAddress) {
|
|
|
|
|
send(res, 400, {
|
|
|
|
|
status: '0',
|
|
|
|
|
message: 'Params contractaddress and sourceCode are required',
|
|
|
|
|
result: null,
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const codeformat = (payload.codeformat || '').toLowerCase();
|
|
|
|
|
const sourceCode = payload.sourceCode ?? payload.source_code;
|
|
|
|
|
const isStandardJson =
|
|
|
|
|
codeformat === 'solidity-standard-json-input' ||
|
|
|
|
|
(typeof sourceCode === 'string' && sourceCode.trimStart().startsWith('{') && sourceCode.includes('"sources"'));
|
|
|
|
|
// Etherscan API expects Standard JSON in sourceCode; flattened Solidity causes "Invalid JSON".
|
feat(omnl): HYBX-BATCH-001 package, rail scripts, regulatory docs, CI
- Add OMNL/CBK Indonesia submission and audit binder docs, manifests, attestations
- Add scripts/omnl transaction-package pipeline, LEI/PvP helpers, jq/lib fixtures
- Update entity master data, MASTER_INDEX, TODOS, dbis-rail docs and rulebook
- Add proof_package/regulatory skeleton and transaction package zip + snapshot JSON
- validate-omnl-rail workflow, forge-verification-proxy tweak, .gitignore hygiene
- Bump smom-dbis-138 (cronos verify docs/scripts) and explorer-monorepo (SPA + env report)
Made-with: Cursor
2026-03-24 18:11:36 -07:00
|
|
|
// Try v2 API first for flattened code; use multipart standard-input when the payload is Standard JSON.
|
2026-02-12 15:46:57 -08:00
|
|
|
const tryV2First = !isStandardJson;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
let result;
|
|
|
|
|
let out;
|
|
|
|
|
if (tryV2First) {
|
|
|
|
|
result = await forwardV2Flattened(payload);
|
|
|
|
|
out = toEtherscanResponse(result);
|
|
|
|
|
if (out.status !== '1') {
|
|
|
|
|
console.error('[forge-verification-proxy] v2 API failed:', out.message, '- trying Etherscan format...');
|
|
|
|
|
result = await forwardEtherscanFormat(payload);
|
|
|
|
|
const etherOut = toEtherscanResponse(result);
|
|
|
|
|
send(res, 200, etherOut.status === '1' ? etherOut : out);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
feat(omnl): HYBX-BATCH-001 package, rail scripts, regulatory docs, CI
- Add OMNL/CBK Indonesia submission and audit binder docs, manifests, attestations
- Add scripts/omnl transaction-package pipeline, LEI/PvP helpers, jq/lib fixtures
- Update entity master data, MASTER_INDEX, TODOS, dbis-rail docs and rulebook
- Add proof_package/regulatory skeleton and transaction package zip + snapshot JSON
- validate-omnl-rail workflow, forge-verification-proxy tweak, .gitignore hygiene
- Bump smom-dbis-138 (cronos verify docs/scripts) and explorer-monorepo (SPA + env report)
Made-with: Cursor
2026-03-24 18:11:36 -07:00
|
|
|
result = await forwardV2StandardInput(payload);
|
2026-02-12 15:46:57 -08:00
|
|
|
out = toEtherscanResponse(result);
|
|
|
|
|
if (out.status !== '1') {
|
feat(omnl): HYBX-BATCH-001 package, rail scripts, regulatory docs, CI
- Add OMNL/CBK Indonesia submission and audit binder docs, manifests, attestations
- Add scripts/omnl transaction-package pipeline, LEI/PvP helpers, jq/lib fixtures
- Update entity master data, MASTER_INDEX, TODOS, dbis-rail docs and rulebook
- Add proof_package/regulatory skeleton and transaction package zip + snapshot JSON
- validate-omnl-rail workflow, forge-verification-proxy tweak, .gitignore hygiene
- Bump smom-dbis-138 (cronos verify docs/scripts) and explorer-monorepo (SPA + env report)
Made-with: Cursor
2026-03-24 18:11:36 -07:00
|
|
|
console.error('[forge-verification-proxy] v2 standard-input failed:', out.message, '- trying Etherscan format...');
|
|
|
|
|
result = await forwardEtherscanFormat(payload);
|
|
|
|
|
const etherOut = toEtherscanResponse(result);
|
|
|
|
|
send(res, 200, etherOut.status === '1' ? etherOut : out);
|
2026-02-12 15:46:57 -08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
send(res, 200, out);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('[forge-verification-proxy]', e.message);
|
|
|
|
|
send(res, 500, {
|
|
|
|
|
status: '0',
|
|
|
|
|
message: e.message || 'Proxy error',
|
|
|
|
|
result: null,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
server.listen(PORT, '0.0.0.0', () => {
|
|
|
|
|
console.log(`[forge-verification-proxy] Listening on port ${PORT}`);
|
|
|
|
|
console.log(`[forge-verification-proxy] Blockscout: ${BLOCKSCOUT_URL}`);
|
|
|
|
|
console.log(`[forge-verification-proxy] Forge: --verifier-url "http://<host>:${PORT}/"`);
|
|
|
|
|
});
|