Files
proxmox/scripts/verify/check-gru-v2-public-protocols.sh
defiQUG dbd517b279 Sync workspace: config, docs, scripts, CI, operator rules, and submodule pointers.
- Update dbis_core, cross-chain-pmm-lps, explorer-monorepo, metamask-integration, pr-workspace/chains
- Omit embedded publish git dirs and empty placeholders from index

Made-with: Cursor
2026-04-12 06:12:20 -07:00

322 lines
14 KiB
Bash

#!/usr/bin/env bash
# Summarize the GRU v2 public-network rollout posture across the public EVM cW*
# mesh, Wave 1 transport activation, and public protocol liquidity.
#
# Usage:
# bash scripts/verify/check-gru-v2-public-protocols.sh
# bash scripts/verify/check-gru-v2-public-protocols.sh --json
# bash scripts/verify/check-gru-v2-public-protocols.sh --write-explorer-config
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
export PROJECT_ROOT
OUTPUT_JSON=0
WRITE_EXPLORER_CONFIG=0
for arg in "$@"; do
case "$arg" in
--json) OUTPUT_JSON=1 ;;
--write-explorer-config) WRITE_EXPLORER_CONFIG=1 ;;
*)
echo "Unknown argument: $arg" >&2
exit 2
;;
esac
done
command -v node >/dev/null 2>&1 || {
echo "[FAIL] Missing required command: node" >&2
exit 1
}
OUTPUT_JSON="$OUTPUT_JSON" WRITE_EXPLORER_CONFIG="$WRITE_EXPLORER_CONFIG" node <<'NODE'
const fs = require('fs');
const path = require('path');
const root = process.env.PROJECT_ROOT;
const outputJson = process.env.OUTPUT_JSON === '1';
const writeExplorerConfig = process.env.WRITE_EXPLORER_CONFIG === '1';
const explorerConfigPath = path.join(
root,
'explorer-monorepo/backend/api/rest/config/metamask/GRU_V2_PUBLIC_DEPLOYMENT_STATUS.json'
);
function readJson(relPath) {
return JSON.parse(fs.readFileSync(path.join(root, relPath), 'utf8'));
}
const rollout = readJson('config/gru-global-priority-currency-rollout.json');
const manifest = readJson('config/gru-iso4217-currency-manifest.json');
const transport = readJson('config/gru-transport-active.json');
const deployment = readJson('cross-chain-pmm-lps/config/deployment-status.json');
const mapping = readJson('config/token-mapping-multichain.json');
const poolMatrix = readJson('cross-chain-pmm-lps/config/pool-matrix.json');
const routingRegistry = readJson('config/routing-registry.json');
const desiredChainIds = rollout.desiredDestinationNetworks?.evmPublicCwMeshChainIds || [];
const chainNames = mapping.chainNames || {};
const manifestByCode = new Map((manifest.currencies || []).map((item) => [item.code, item]));
const transportBySymbol = new Map((transport.enabledCanonicalTokens || []).map((item) => [item.symbol, item]));
const coreCwSymbols = [
'cWUSDT',
'cWUSDC',
'cWEURC',
'cWEURT',
'cWGBPC',
'cWGBPT',
'cWAUDC',
'cWJPYC',
'cWCHFC',
'cWCADC',
'cWXAUC',
'cWXAUT'
];
const publicProtocols = [
{ key: 'uniswap_v3', name: 'Uniswap v3' },
{ key: 'balancer', name: 'Balancer' },
{ key: 'curve_3', name: 'Curve 3' },
{ key: 'dodo_pmm', name: 'DODO PMM' },
{ key: 'one_inch', name: '1inch' }
];
const desiredChainRows = desiredChainIds.map((chainId) => {
const chain = deployment.chains?.[String(chainId)] || {};
const cwTokens = Object.keys(chain.cwTokens || {});
const pmmPools = Array.isArray(chain.pmmPools) ? chain.pmmPools : [];
return {
chainId,
name: chain.name || chainNames[String(chainId)] || `Chain ${chainId}`,
cwTokenCount: cwTokens.length,
hasFullCoreSuite: coreCwSymbols.every((symbol) => cwTokens.includes(symbol)),
bridgeAvailable: chain.bridgeAvailable === true,
pmmPoolCount: pmmPools.length
};
});
const desiredButNotLoaded = desiredChainRows.filter((row) => row.cwTokenCount === 0);
const loadedChains = desiredChainRows.filter((row) => row.cwTokenCount > 0);
const fullCoreSuiteChains = desiredChainRows.filter((row) => row.hasFullCoreSuite);
const chainsWithAnyPools = desiredChainRows.filter((row) => row.pmmPoolCount > 0);
const totalRecordedPublicPools = desiredChainRows.reduce((sum, row) => sum + row.pmmPoolCount, 0);
const arbitrumRoute = (routingRegistry.routes || []).find((route) => route.fromChain === 138 && route.toChain === 42161 && route.asset === 'WETH');
const arbitrumHubBlocker = {
active: true,
fromChain: 138,
viaChain: 1,
toChain: 42161,
currentPath: '138 -> Mainnet -> Arbitrum',
sourceBridge: '0xc9901ce2Ddb6490FAA183645147a87496d8b20B6',
failedTxHash: '0x97df657f0e31341ca852666766e553650531bbcc86621246d041985d7261bb07',
note: (arbitrumRoute && arbitrumRoute.note) || 'Use Mainnet hub; the current Mainnet -> Arbitrum WETH9 leg is blocked.'
};
function currencyState(code) {
const item = manifestByCode.get(code);
return {
manifestPresent: Boolean(item),
deployed: Boolean(item?.status?.deployed),
transportActive: Boolean(item?.status?.transportActive),
x402Ready: Boolean(item?.status?.x402Ready)
};
}
const allAssetResults = (rollout.assets || []).map((asset) => {
const state = currencyState(asset.code);
const transportSymbols = (asset.tokenForms || []).map((item) => item.canonicalSymbol);
const enabledByOverlay = transportSymbols.some((symbol) => transportBySymbol.has(symbol));
return {
code: asset.code,
name: asset.name,
wave: asset.wave,
manifestPresent: state.manifestPresent,
deployed: state.deployed,
transportActive: state.transportActive && enabledByOverlay,
x402Ready: state.x402Ready,
canonicalSymbols: (asset.tokenForms || []).map((item) => item.canonicalSymbol),
wrappedSymbols: (asset.tokenForms || []).map((item) => item.wrappedSymbol)
};
});
const wave1Results = allAssetResults
.filter((asset) => asset.wave === 'wave1')
.map((asset) => ({
...asset,
currentState: asset.transportActive
? 'live_transport'
: asset.deployed
? 'canonical_only'
: asset.manifestPresent
? 'manifest_only'
: 'backlog',
nextStep: asset.transportActive
? 'monitor_and_scale'
: asset.deployed
? 'activate_transport_and_attach_public_liquidity'
: asset.manifestPresent
? 'finish_canonical_deployment'
: 'add_to_manifest'
}));
const wave1WrappedSymbols = [...new Set(wave1Results.flatMap((asset) => asset.wrappedSymbols))];
const poolMatrixCwTokens = new Set(poolMatrix.cwTokens || []);
const wave1WrappedSymbolsMissingFromPoolMatrix = wave1WrappedSymbols.filter((symbol) => !poolMatrixCwTokens.has(symbol));
const rolloutSummary = {
liveTransportAssets: allAssetResults.filter((asset) => asset.transportActive).length,
canonicalOnlyAssets: allAssetResults.filter((asset) => asset.deployed && !asset.transportActive).length,
backlogAssets: allAssetResults.filter((asset) => !asset.manifestPresent).length,
wave1LiveTransport: wave1Results.filter((asset) => asset.currentState === 'live_transport').length,
wave1CanonicalOnly: wave1Results.filter((asset) => asset.currentState === 'canonical_only').length,
wave1WrappedSymbols: wave1WrappedSymbols.length,
wave1WrappedSymbolsCoveredByPoolMatrix: wave1WrappedSymbols.length - wave1WrappedSymbolsMissingFromPoolMatrix.length
};
const protocolResults = publicProtocols.map((protocol) => {
if (protocol.key === 'dodo_pmm') {
return {
key: protocol.key,
name: protocol.name,
activePublicCwPools: totalRecordedPublicPools,
destinationChainsWithPools: chainsWithAnyPools.length,
status: totalRecordedPublicPools > 0 ? 'partial_live_on_public_cw_mesh' : 'not_deployed_on_public_cw_mesh',
notes: totalRecordedPublicPools > 0
? 'deployment-status.json now records live public-chain cW* DODO PMM pools on Mainnet, including recorded non-USD Wave 1 rows, and the recorded Mainnet pools now have bidirectional live execution proof. The broader public cW mesh is still partial.'
: 'cross-chain-pmm-lps/config/deployment-status.json still records no public-chain cW* pools, so no live DODO PMM cW venue can be asserted.'
};
}
return {
key: protocol.key,
name: protocol.name,
activePublicCwPools: 0,
destinationChainsWithPools: 0,
status: 'not_deployed_on_public_cw_mesh',
notes: 'No live public-chain cW* venue is recorded for this protocol in deployment-status.json yet.'
};
});
const blockers = [];
if (desiredButNotLoaded.length > 0) {
blockers.push(`Desired public EVM targets still lack cW token suites: ${desiredButNotLoaded.map((row) => row.name).join(', ')}.`);
}
if (rolloutSummary.wave1CanonicalOnly > 0) {
blockers.push(`Wave 1 GRU assets are still canonical-only on Chain 138: ${wave1Results.filter((asset) => asset.currentState === 'canonical_only').map((asset) => asset.code).join(', ')}.`);
}
if (wave1WrappedSymbolsMissingFromPoolMatrix.length > 0) {
blockers.push(`Wave 1 wrapped symbols are still missing from the public pool matrix: ${wave1WrappedSymbolsMissingFromPoolMatrix.join(', ')}.`);
}
if (chainsWithAnyPools.length === 0) {
blockers.push('Public cW* liquidity is still undeployed across Uniswap v3, Balancer, Curve 3, DODO PMM, and 1inch on the tracked public-network mesh.');
}
if (chainsWithAnyPools.length > 0 && protocolResults.some((item) => item.activePublicCwPools > 0) && protocolResults.some((item) => item.activePublicCwPools === 0)) {
blockers.push('Public cW* protocol rollout is now partial: DODO PMM has recorded pools, while Uniswap v3, Balancer, Curve 3, and 1inch remain not live on the public cW mesh.');
}
if (rolloutSummary.backlogAssets > 0) {
blockers.push(`The ranked GRU global rollout still has ${rolloutSummary.backlogAssets} backlog assets outside the live manifest.`);
}
if ((rollout.desiredDestinationNetworks?.nonEvmRelayPrograms || []).length > 0) {
blockers.push(`Desired non-EVM GRU targets remain planned / relay-dependent: ${(rollout.desiredDestinationNetworks.nonEvmRelayPrograms || []).map((item) => item.identifier).join(', ')}.`);
}
if (arbitrumHubBlocker.active) {
blockers.push(`Arbitrum public-network bootstrap remains blocked on the current Mainnet hub leg: tx ${arbitrumHubBlocker.failedTxHash} reverted from ${arbitrumHubBlocker.sourceBridge} before any bridge event was emitted.`);
}
const report = {
generatedAt: new Date().toISOString(),
canonicalChainId: 138,
summary: {
desiredPublicEvmTargets: desiredChainRows.length,
loadedPublicEvmChains: loadedChains.length,
loadedPublicEvmFullCoreSuite: fullCoreSuiteChains.length,
desiredButNotLoaded: desiredButNotLoaded.length,
publicProtocolsTracked: protocolResults.length,
publicProtocolsWithActiveCwPools: protocolResults.filter((item) => item.activePublicCwPools > 0).length,
chainsWithAnyRecordedPublicCwPools: chainsWithAnyPools.length,
liveTransportAssets: rolloutSummary.liveTransportAssets,
wave1CanonicalOnly: rolloutSummary.wave1CanonicalOnly,
backlogAssets: rolloutSummary.backlogAssets
},
publicEvmMesh: {
coreCwSuite: coreCwSymbols,
desiredChains: desiredChainRows,
desiredButNotLoaded: desiredButNotLoaded.map((row) => ({ chainId: row.chainId, name: row.name })),
wave1PoolMatrixCoverage: {
totalWrappedSymbols: wave1WrappedSymbols.length,
coveredSymbols: rolloutSummary.wave1WrappedSymbolsCoveredByPoolMatrix,
missingSymbols: wave1WrappedSymbolsMissingFromPoolMatrix
},
note: desiredButNotLoaded.length > 0
? `The public EVM cW token mesh is complete on the currently loaded ${loadedChains.length}-chain set, but ${desiredButNotLoaded.map((row) => row.name).join(', ')} ${desiredButNotLoaded.length === 1 ? 'remains a desired target without a cW suite' : 'remain desired targets without cW suites'} in deployment-status.json.`
: `The public EVM cW token mesh is complete across all ${loadedChains.length} desired public EVM targets recorded in deployment-status.json.`
},
transport: {
liveTransportAssets: allAssetResults.filter((asset) => asset.transportActive).map((asset) => ({ code: asset.code, name: asset.name })),
wave1: wave1Results,
note: 'USD is the only live transport asset today. Wave 1 non-USD assets are deployed canonically on Chain 138 but are not yet promoted into the active transport overlay.'
},
protocols: {
publicCwMesh: protocolResults,
chain138CanonicalVenues: {
note: 'Chain 138 canonical routing is a separate surface: DODO PMM plus upstream-native Uniswap v3 and the funded pilot-compatible Balancer, Curve 3, and 1inch venues are live there.',
liveProtocols: ['DODO PMM', 'Uniswap v3', 'Balancer', 'Curve 3', '1inch']
}
},
bridgeRouteHealth: {
arbitrumHubBlocker
},
explorer: {
tokenListApi: 'https://explorer.d-bis.org/api/config/token-list',
staticStatusPath: 'https://explorer.d-bis.org/config/GRU_V2_PUBLIC_DEPLOYMENT_STATUS.json'
},
blockers
};
if (writeExplorerConfig) {
fs.writeFileSync(explorerConfigPath, `${JSON.stringify(report, null, 2)}\n`);
}
if (outputJson) {
console.log(JSON.stringify(report, null, 2));
process.exit(0);
}
console.log('=== GRU V2 Public-Protocol Rollout Status ===');
console.log(`Desired public EVM targets: ${report.summary.desiredPublicEvmTargets}`);
console.log(`Loaded public EVM chains: ${report.summary.loadedPublicEvmChains}`);
console.log(`Loaded chains with full core cW suite: ${report.summary.loadedPublicEvmFullCoreSuite}`);
console.log(`Desired targets still unloaded: ${report.summary.desiredButNotLoaded}`);
console.log(`Live transport assets: ${report.summary.liveTransportAssets}`);
console.log(`Wave 1 canonical-only assets: ${report.summary.wave1CanonicalOnly}`);
console.log(`Wave 1 wrapped symbols covered by pool-matrix: ${report.publicEvmMesh.wave1PoolMatrixCoverage.coveredSymbols}/${report.publicEvmMesh.wave1PoolMatrixCoverage.totalWrappedSymbols}`);
console.log(`Backlog assets: ${report.summary.backlogAssets}`);
console.log(`Tracked public protocols: ${report.summary.publicProtocolsTracked}`);
console.log(`Protocols with active public cW pools: ${report.summary.publicProtocolsWithActiveCwPools}`);
console.log(`Chains with any recorded public cW pools: ${report.summary.chainsWithAnyRecordedPublicCwPools}`);
console.log('');
console.log('Wave 1:');
for (const asset of wave1Results) {
console.log(`- ${asset.code} (${asset.name}) -> ${asset.currentState}; next: ${asset.nextStep}`);
}
console.log('');
console.log('Public protocol surface:');
for (const protocol of protocolResults) {
console.log(`- ${protocol.name}: ${protocol.status}`);
}
if (blockers.length > 0) {
console.log('');
console.log('Active blockers:');
for (const blocker of blockers) {
console.log(`- ${blocker}`);
}
}
if (writeExplorerConfig) {
console.log('');
console.log(`Wrote: ${explorerConfigPath}`);
}
NODE