- 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
490 lines
22 KiB
Bash
490 lines
22 KiB
Bash
#!/usr/bin/env bash
|
|
# Generate an operator-grade GRU v2 public deployment queue across Wave 1
|
|
# transport activation, public-chain cW pool deployment, and protocol staging.
|
|
#
|
|
# Usage:
|
|
# bash scripts/verify/check-gru-v2-deployment-queue.sh
|
|
# bash scripts/verify/check-gru-v2-deployment-queue.sh --json
|
|
# bash scripts/verify/check-gru-v2-deployment-queue.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_DEPLOYMENT_QUEUE.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 poolMatrix = readJson('cross-chain-pmm-lps/config/pool-matrix.json');
|
|
const protocolPlan = readJson('config/gru-v2-public-protocol-rollout-plan.json');
|
|
const mapping = readJson('config/token-mapping-multichain.json');
|
|
const routingRegistry = readJson('config/routing-registry.json');
|
|
|
|
const manifestByCode = new Map((manifest.currencies || []).map((item) => [item.code, item]));
|
|
const transportSymbols = new Set((transport.enabledCanonicalTokens || []).map((item) => item.symbol));
|
|
const desiredChainIds = rollout.desiredDestinationNetworks?.evmPublicCwMeshChainIds || [];
|
|
const poolMatrixTokens = new Set(poolMatrix.cwTokens || []);
|
|
const cToCw = mapping.cToCwSymbolMapping || {};
|
|
|
|
const wave1Assets = (rollout.assets || []).filter((asset) => asset.wave === 'wave1');
|
|
const wave1WrappedSymbols = [...new Set(wave1Assets.flatMap((asset) => (asset.tokenForms || []).map((item) => item.wrappedSymbol)))];
|
|
const wave1CanonicalSymbols = [...new Set(wave1Assets.flatMap((asset) => (asset.tokenForms || []).map((item) => item.canonicalSymbol)))];
|
|
const poolMatrixMissingWave1 = wave1WrappedSymbols.filter((symbol) => !poolMatrixTokens.has(symbol));
|
|
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 deriveRepoState(bits) {
|
|
if (bits.transportActive) return 'live_transport';
|
|
if (bits.canonical138Deployed) return 'canonical_only';
|
|
if (bits.manifestPresent) return 'manifest_only';
|
|
if (bits.cToCwMapped) return 'mapping_only';
|
|
return 'backlog';
|
|
}
|
|
|
|
const allAssetResults = (rollout.assets || []).map((asset) => {
|
|
const manifestEntry = manifestByCode.get(asset.code);
|
|
const canonicalSymbols = (asset.tokenForms || []).map((item) => item.canonicalSymbol);
|
|
const wrappedSymbols = (asset.tokenForms || []).map((item) => item.wrappedSymbol);
|
|
const manifestPresent = Boolean(manifestEntry);
|
|
const canonical138Deployed = Boolean(manifestEntry?.status?.deployed);
|
|
const transportActive = canonicalSymbols.some((symbol) => transportSymbols.has(symbol));
|
|
const cToCwMapped = canonicalSymbols.length > 0 && canonicalSymbols.every((symbol, idx) => cToCw[symbol] === wrappedSymbols[idx]);
|
|
return {
|
|
code: asset.code,
|
|
wave: asset.wave,
|
|
currentRepoState: deriveRepoState({
|
|
manifestPresent,
|
|
canonical138Deployed,
|
|
cToCwMapped,
|
|
transportActive
|
|
})
|
|
};
|
|
});
|
|
|
|
const rolloutBacklogAssets = allAssetResults.filter((item) => item.currentRepoState === 'backlog').length;
|
|
|
|
function normalizePair(pair) {
|
|
return String(pair || '').trim().toUpperCase();
|
|
}
|
|
|
|
function poolEntryMatchesPair(entry, pair) {
|
|
const normalized = normalizePair(pair);
|
|
const [base, quote] = normalized.split('/');
|
|
const baseCandidate = String(entry.base || entry.base_token || '').trim().toUpperCase();
|
|
const quoteCandidate = String(entry.quote || entry.quote_token || '').trim().toUpperCase();
|
|
return baseCandidate === base && quoteCandidate === quote;
|
|
}
|
|
|
|
const assetQueue = wave1Assets.map((asset) => {
|
|
const manifestEntry = manifestByCode.get(asset.code);
|
|
const canonicalSymbols = (asset.tokenForms || []).map((item) => item.canonicalSymbol);
|
|
const wrappedSymbols = (asset.tokenForms || []).map((item) => item.wrappedSymbol);
|
|
const transportActive = canonicalSymbols.some((symbol) => transportSymbols.has(symbol));
|
|
const coveredByPoolMatrix = wrappedSymbols.every((symbol) => poolMatrixTokens.has(symbol));
|
|
return {
|
|
code: asset.code,
|
|
name: asset.name,
|
|
canonicalSymbols,
|
|
wrappedSymbols,
|
|
transportActive,
|
|
canonicalDeployed: Boolean(manifestEntry?.status?.deployed),
|
|
x402Ready: Boolean(manifestEntry?.status?.x402Ready),
|
|
coveredByPoolMatrix,
|
|
nextSteps: transportActive
|
|
? ['monitor_live_transport', 'deploy_public_pools']
|
|
: ['enable_bridge_controls', 'set_max_outstanding', 'promote_transport_overlay', 'deploy_public_pools']
|
|
};
|
|
});
|
|
|
|
const chainQueue = desiredChainIds.map((chainId) => {
|
|
const chain = deployment.chains?.[String(chainId)] || {};
|
|
const matrix = poolMatrix.chains?.[String(chainId)] || {};
|
|
const cwTokens = Object.keys(chain.cwTokens || {});
|
|
const pmmPools = Array.isArray(chain.pmmPools) ? chain.pmmPools : [];
|
|
const plannedWave1Pairs = (matrix.poolsFirst || []).filter((pair) => {
|
|
return wave1WrappedSymbols.some((symbol) => normalizePair(pair).startsWith(`${symbol.toUpperCase()}/`));
|
|
});
|
|
const recordedWave1Pairs = plannedWave1Pairs.filter((pair) => pmmPools.some((entry) => poolEntryMatchesPair(entry, pair)));
|
|
return {
|
|
chainId,
|
|
name: matrix.name || chain.name || `Chain ${chainId}`,
|
|
hubStable: matrix.hubStable || null,
|
|
bridgeAvailable: chain.bridgeAvailable === true,
|
|
cwTokenCount: cwTokens.length,
|
|
wave1WrappedCoverage: wave1WrappedSymbols.filter((symbol) => cwTokens.includes(symbol)).length,
|
|
plannedWave1Pairs,
|
|
recordedWave1Pairs,
|
|
nextStep: cwTokens.length === 0
|
|
? 'complete_cw_suite_then_deploy_pools'
|
|
: recordedWave1Pairs.length === plannedWave1Pairs.length && plannedWave1Pairs.length > 0
|
|
? 'verify_and_route'
|
|
: 'deploy_first_tier_wave1_pools'
|
|
};
|
|
});
|
|
|
|
const totalRecordedPublicPools = desiredChainIds.reduce((sum, chainId) => {
|
|
const chain = deployment.chains?.[String(chainId)] || {};
|
|
const pmmPools = Array.isArray(chain.pmmPools) ? chain.pmmPools : [];
|
|
return sum + pmmPools.length;
|
|
}, 0);
|
|
|
|
const protocolQueue = (protocolPlan.protocols || []).map((protocol) => {
|
|
if (protocol.key === 'dodo_v3_d3mm') {
|
|
return {
|
|
key: protocol.key,
|
|
name: protocol.name,
|
|
role: protocol.role,
|
|
deploymentStage: protocol.deploymentStage,
|
|
activePublicPools: 0,
|
|
currentState: 'pilot_live_chain138_only',
|
|
activationDependsOn: protocol.activationDependsOn || []
|
|
};
|
|
}
|
|
|
|
if (protocol.key === 'dodo_pmm') {
|
|
return {
|
|
key: protocol.key,
|
|
name: protocol.name,
|
|
role: protocol.role,
|
|
deploymentStage: protocol.deploymentStage,
|
|
activePublicPools: totalRecordedPublicPools,
|
|
currentState: totalRecordedPublicPools > 0 ? 'partially_live_on_public_cw_mesh' : 'queued_not_live',
|
|
activationDependsOn: protocol.activationDependsOn || []
|
|
};
|
|
}
|
|
|
|
return {
|
|
key: protocol.key,
|
|
name: protocol.name,
|
|
role: protocol.role,
|
|
deploymentStage: protocol.deploymentStage,
|
|
activePublicPools: 0,
|
|
currentState: 'queued_not_live',
|
|
activationDependsOn: protocol.activationDependsOn || []
|
|
};
|
|
});
|
|
|
|
const summary = {
|
|
wave1Assets: assetQueue.length,
|
|
wave1TransportActive: assetQueue.filter((item) => item.transportActive).length,
|
|
wave1TransportPending: assetQueue.filter((item) => !item.transportActive).length,
|
|
wave1WrappedSymbols: wave1WrappedSymbols.length,
|
|
wave1WrappedSymbolsCoveredByPoolMatrix: wave1WrappedSymbols.length - poolMatrixMissingWave1.length,
|
|
wave1WrappedSymbolsMissingFromPoolMatrix: poolMatrixMissingWave1.length,
|
|
desiredPublicEvmTargets: chainQueue.length,
|
|
chainsWithLoadedCwSuites: chainQueue.filter((item) => item.cwTokenCount > 0).length,
|
|
chainsMissingCwSuites: chainQueue.filter((item) => item.cwTokenCount === 0).length,
|
|
firstTierWave1PoolsPlanned: chainQueue.reduce((sum, item) => sum + item.plannedWave1Pairs.length, 0),
|
|
firstTierWave1PoolsRecordedLive: chainQueue.reduce((sum, item) => sum + item.recordedWave1Pairs.length, 0),
|
|
protocolsTracked: protocolQueue.length,
|
|
protocolsLive: protocolQueue.filter((item) => item.activePublicPools > 0).length
|
|
};
|
|
|
|
const blockers = [];
|
|
if (poolMatrixMissingWave1.length > 0) {
|
|
blockers.push(`Wave 1 wrapped symbols missing from pool-matrix: ${poolMatrixMissingWave1.join(', ')}.`);
|
|
}
|
|
const missingSuiteChains = chainQueue.filter((item) => item.cwTokenCount === 0);
|
|
if (missingSuiteChains.length > 0) {
|
|
blockers.push(`Desired public EVM targets still missing cW suites: ${missingSuiteChains.map((item) => item.name).join(', ')}.`);
|
|
}
|
|
const pendingWave1 = assetQueue.filter((item) => !item.transportActive);
|
|
if (pendingWave1.length > 0) {
|
|
blockers.push(`Wave 1 transport is still pending for: ${pendingWave1.map((item) => item.code).join(', ')}.`);
|
|
}
|
|
if (summary.firstTierWave1PoolsRecordedLive === 0) {
|
|
blockers.push('No first-tier Wave 1 public cW pools are recorded live yet across the tracked public EVM mesh.');
|
|
}
|
|
if (protocolQueue.every((item) => item.activePublicPools === 0)) {
|
|
blockers.push('All tracked public protocols remain queued: Uniswap v3, DODO PMM, Balancer, Curve 3, and 1inch.');
|
|
}
|
|
if (arbitrumHubBlocker.active) {
|
|
blockers.push(`Arbitrum bootstrap remains blocked on the current Mainnet hub leg: tx ${arbitrumHubBlocker.failedTxHash} reverted before any bridge event was emitted.`);
|
|
}
|
|
|
|
const resolutionMatrix = [
|
|
{
|
|
key: 'mainnet_arbitrum_hub_blocked',
|
|
state: arbitrumHubBlocker.active ? 'open' : 'resolved',
|
|
blocker: arbitrumHubBlocker.active
|
|
? `Arbitrum bootstrap remains blocked on the current Mainnet hub leg: tx ${arbitrumHubBlocker.failedTxHash} reverted from ${arbitrumHubBlocker.sourceBridge} before any bridge event was emitted.`
|
|
: 'The Mainnet -> Arbitrum WETH9 hub leg is healthy.',
|
|
targets: [
|
|
{
|
|
fromChain: arbitrumHubBlocker.fromChain,
|
|
viaChain: arbitrumHubBlocker.viaChain,
|
|
toChain: arbitrumHubBlocker.toChain,
|
|
currentPath: arbitrumHubBlocker.currentPath
|
|
}
|
|
],
|
|
resolution: [
|
|
'Repair or replace the current Mainnet WETH9 fan-out bridge before treating Arbitrum as an available public bootstrap target.',
|
|
'Retest 138 -> Mainnet first-hop delivery, then rerun a smaller Mainnet -> Arbitrum send and require destination bridge events before promoting the route.',
|
|
'Keep Arbitrum marked blocked in the explorer and status surfaces until the hub leg emits and completes normally.'
|
|
],
|
|
runbooks: [
|
|
'docs/07-ccip/CROSS_NETWORK_FUNDING_BOOTSTRAP_STRATEGY.md',
|
|
'docs/07-ccip/CHAIN138_PUBLIC_CHAIN_UNLOAD_ROUTES.md',
|
|
'docs/00-meta/REQUIRED_FIXES_GAPS_AND_DEPLOYMENTS_LIST.md'
|
|
],
|
|
exitCriteria: 'A fresh Mainnet -> Arbitrum WETH9 send emits bridge events and completes destination delivery successfully.'
|
|
},
|
|
{
|
|
key: 'missing_public_cw_suites',
|
|
state: missingSuiteChains.length === 0 ? 'resolved' : 'open',
|
|
blocker: missingSuiteChains.length === 0
|
|
? 'All desired public EVM targets have cW suites.'
|
|
: `Desired public EVM targets still missing cW suites: ${missingSuiteChains.map((item) => item.name).join(', ')}.`,
|
|
targets: missingSuiteChains.map((item) => ({
|
|
chainId: item.chainId,
|
|
name: item.name,
|
|
nextStep: item.nextStep
|
|
})),
|
|
resolution: [
|
|
'Deploy the full cW core suite on each missing destination chain using the existing CW deploy-and-wire flow.',
|
|
'Grant bridge mint/burn roles and mark the corridor live in cross-chain-pmm-lps/config/deployment-status.json.',
|
|
'Update public token lists / explorer config, then rerun check-cw-evm-deployment-mesh.sh and check-cw-public-pool-status.sh.'
|
|
],
|
|
runbooks: [
|
|
'docs/07-ccip/CW_DEPLOY_AND_WIRE_RUNBOOK.md',
|
|
'docs/03-deployment/PHASE_C_CW_AND_EDGE_POOLS_RUNBOOK.md',
|
|
'scripts/deployment/run-cw-remaining-steps.sh',
|
|
'scripts/verify/check-cw-evm-deployment-mesh.sh'
|
|
],
|
|
exitCriteria: missingSuiteChains.length === 0
|
|
? 'All desired public EVM targets report non-zero cW suites and bridgeAvailable=true in deployment-status.json.'
|
|
: `${missingSuiteChains.map((item) => item.name).join(', ')} report non-zero cW suites and become bridgeAvailable in deployment-status.json.`
|
|
},
|
|
{
|
|
key: 'wave1_transport_pending',
|
|
state: pendingWave1.length === 0 ? 'resolved' : 'open',
|
|
blocker: pendingWave1.length === 0
|
|
? 'Wave 1 transport is fully active.'
|
|
: `Wave 1 transport is still pending for: ${pendingWave1.map((item) => item.code).join(', ')}.`,
|
|
targets: pendingWave1.map((item) => ({
|
|
code: item.code,
|
|
canonicalSymbols: item.canonicalSymbols,
|
|
wrappedSymbols: item.wrappedSymbols
|
|
})),
|
|
resolution: [
|
|
'Enable bridge controls and supervision policy for each Wave 1 canonical asset on Chain 138.',
|
|
'Set max-outstanding / capacity controls, then promote the canonical symbols into config/gru-transport-active.json.',
|
|
'Verify the overlay promotion with check-gru-global-priority-rollout.sh and check-gru-v2-chain138-readiness.sh before attaching public liquidity.'
|
|
],
|
|
runbooks: [
|
|
'docs/04-configuration/GRU_GLOBAL_PRIORITY_CROSS_CHAIN_ROLLOUT.md',
|
|
'docs/04-configuration/GRU_TRANSPORT_ACTIVE_JSON.md',
|
|
'scripts/verify/check-gru-global-priority-rollout.sh',
|
|
'scripts/verify/check-gru-v2-chain138-readiness.sh'
|
|
],
|
|
exitCriteria: 'Wave 1 transport pending count reaches zero and the overlay reports the seven non-USD assets as live_transport.'
|
|
},
|
|
{
|
|
key: 'first_tier_public_pools_not_live',
|
|
state: summary.firstTierWave1PoolsRecordedLive > 0 ? 'in_progress' : 'open',
|
|
blocker: summary.firstTierWave1PoolsRecordedLive > 0
|
|
? 'Some first-tier Wave 1 public cW pools are live, but the rollout is incomplete.'
|
|
: 'No first-tier Wave 1 public cW pools are recorded live yet across the tracked public EVM mesh.',
|
|
targets: chainQueue.map((item) => ({
|
|
chainId: item.chainId,
|
|
name: item.name,
|
|
hubStable: item.hubStable,
|
|
plannedWave1Pairs: item.plannedWave1Pairs.length,
|
|
recordedWave1Pairs: item.recordedWave1Pairs.length
|
|
})),
|
|
resolution: [
|
|
'Deploy the first-tier cW/hub-stable pairs from pool-matrix.json on every chain with a loaded cW suite.',
|
|
'Seed the new pools with initial liquidity and record the resulting pool addresses in cross-chain-pmm-lps/config/deployment-status.json.',
|
|
'Use check-cw-public-pool-status.sh to verify the mesh is no longer empty before surfacing the venues publicly.'
|
|
],
|
|
runbooks: [
|
|
'docs/03-deployment/SINGLE_SIDED_LPS_PUBLIC_NETWORKS_RUNBOOK.md',
|
|
'docs/03-deployment/PMM_FULL_MESH_AND_PUBLIC_SINGLE_SIDED_PLAN.md',
|
|
'cross-chain-pmm-lps/config/pool-matrix.json',
|
|
'scripts/verify/check-cw-public-pool-status.sh'
|
|
],
|
|
exitCriteria: 'First-tier Wave 1 pools are recorded live in deployment-status.json and check-cw-public-pool-status.sh reports non-zero pool coverage.'
|
|
},
|
|
{
|
|
key: 'public_protocols_queued',
|
|
state: protocolQueue.every((item) => item.activePublicPools === 0) ? 'open' : 'in_progress',
|
|
blocker: protocolQueue.every((item) => item.activePublicPools === 0)
|
|
? 'All tracked public protocols remain queued: Uniswap v3, DODO PMM, Balancer, Curve 3, and 1inch.'
|
|
: 'Some tracked public protocols have begun activation, but the full protocol stack is not live yet.',
|
|
targets: protocolQueue.map((item) => ({
|
|
key: item.key,
|
|
name: item.name,
|
|
deploymentStage: item.deploymentStage,
|
|
activationDependsOn: item.activationDependsOn
|
|
})),
|
|
resolution: [
|
|
'Stage 1: activate Uniswap v3 and DODO PMM once first-tier cW pools exist on the public mesh.',
|
|
'Stage 2: activate Balancer and Curve 3 only after first-tier stable liquidity is already live.',
|
|
'Stage 3: expose 1inch after the underlying pools, routing/indexer visibility, and public provider-capability wiring are in place.'
|
|
],
|
|
runbooks: [
|
|
'config/gru-v2-public-protocol-rollout-plan.json',
|
|
'docs/11-references/GRU_V2_PUBLIC_PROTOCOL_DEPLOYMENT_STATUS.md',
|
|
'scripts/verify/check-gru-v2-public-protocols.sh'
|
|
],
|
|
exitCriteria: 'The public protocol status surface reports non-zero active cW pools for the staged venues.'
|
|
},
|
|
{
|
|
key: 'global_priority_backlog',
|
|
state: rolloutBacklogAssets === 0 ? 'resolved' : 'open',
|
|
blocker: rolloutBacklogAssets === 0
|
|
? 'No ranked GRU backlog assets remain outside the live manifest.'
|
|
: `The ranked GRU global rollout still has ${rolloutBacklogAssets} backlog assets outside the live manifest.`,
|
|
targets: [
|
|
{ backlogAssets: rolloutBacklogAssets }
|
|
],
|
|
resolution: [
|
|
'Complete Wave 1 transport and first-tier public liquidity before promoting the remaining ranked assets.',
|
|
'For each backlog asset, add canonical + wrapped symbols to the manifest/rollout plan, deploy contracts, and extend the public pool matrix.',
|
|
'Promote each new asset through the same transport and public-liquidity gates used for Wave 1.'
|
|
],
|
|
runbooks: [
|
|
'config/gru-global-priority-currency-rollout.json',
|
|
'config/gru-iso4217-currency-manifest.json',
|
|
'docs/04-configuration/GRU_GLOBAL_PRIORITY_CROSS_CHAIN_ROLLOUT.md',
|
|
'scripts/verify/check-gru-global-priority-rollout.sh'
|
|
],
|
|
exitCriteria: 'Backlog assets count reaches zero in check-gru-global-priority-rollout.sh.'
|
|
},
|
|
{
|
|
key: 'solana_non_evm_program',
|
|
state: ((rollout.desiredDestinationNetworks?.nonEvmRelayPrograms || []).length || 0) === 0 ? 'resolved' : 'planned',
|
|
blocker: ((rollout.desiredDestinationNetworks?.nonEvmRelayPrograms || []).length || 0) === 0
|
|
? 'No desired non-EVM GRU targets remain.'
|
|
: `Desired non-EVM GRU targets remain planned / relay-dependent: ${(rollout.desiredDestinationNetworks.nonEvmRelayPrograms || []).map((item) => item.identifier).join(', ')}.`,
|
|
targets: (rollout.desiredDestinationNetworks?.nonEvmRelayPrograms || []).map((item) => ({
|
|
identifier: item.identifier,
|
|
label: item.label || item.identifier
|
|
})),
|
|
resolution: [
|
|
'Define the destination-chain token/program model first: SPL or wrapped-account representation, authority model, and relay custody surface.',
|
|
'Implement the relay/program path and only then promote Solana from desired-target status into the active transport inventory.',
|
|
'Add dedicated verifier coverage before marking Solana live anywhere in the explorer or status docs.'
|
|
],
|
|
runbooks: [
|
|
'docs/04-configuration/ADDITIONAL_PATHS_AND_EXTENSIONS.md',
|
|
'docs/04-configuration/GRU_GLOBAL_PRIORITY_CROSS_CHAIN_ROLLOUT.md'
|
|
],
|
|
exitCriteria: 'Solana has a real relay/program surface, a verifier, and is no longer only listed as a desired non-EVM target.'
|
|
}
|
|
];
|
|
|
|
const report = {
|
|
generatedAt: new Date().toISOString(),
|
|
summary,
|
|
assetQueue,
|
|
chainQueue,
|
|
protocolQueue,
|
|
blockers,
|
|
resolutionMatrix,
|
|
notes: [
|
|
'This queue is an operator/deployment planning surface. It does not mark queued pools or transports as live.',
|
|
'Chain 138 canonical venues remain a separate live surface from the public cW mesh.'
|
|
]
|
|
};
|
|
|
|
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 Deployment Queue ===');
|
|
console.log(`Wave 1 assets: ${summary.wave1Assets}`);
|
|
console.log(`Wave 1 transport active: ${summary.wave1TransportActive}`);
|
|
console.log(`Wave 1 transport pending: ${summary.wave1TransportPending}`);
|
|
console.log(`Wave 1 wrapped symbols covered by pool-matrix: ${summary.wave1WrappedSymbolsCoveredByPoolMatrix}/${summary.wave1WrappedSymbols}`);
|
|
console.log(`Desired public EVM targets: ${summary.desiredPublicEvmTargets}`);
|
|
console.log(`Chains with loaded cW suites: ${summary.chainsWithLoadedCwSuites}`);
|
|
console.log(`Chains missing cW suites: ${summary.chainsMissingCwSuites}`);
|
|
console.log(`First-tier Wave 1 pools planned: ${summary.firstTierWave1PoolsPlanned}`);
|
|
console.log(`First-tier Wave 1 pools recorded live: ${summary.firstTierWave1PoolsRecordedLive}`);
|
|
console.log(`Tracked protocols: ${summary.protocolsTracked}`);
|
|
console.log('');
|
|
console.log('Wave 1 asset queue:');
|
|
for (const asset of assetQueue) {
|
|
console.log(`- ${asset.code}: transport=${asset.transportActive ? 'live' : 'pending'}; pool-matrix=${asset.coveredByPoolMatrix ? 'covered' : 'missing'}; next=${asset.nextSteps.join(',')}`);
|
|
}
|
|
console.log('');
|
|
console.log('Per-chain queue:');
|
|
for (const chain of chainQueue) {
|
|
console.log(`- ${chain.chainId} ${chain.name}: hub=${chain.hubStable || 'n/a'}; cw=${chain.cwTokenCount}; plannedWave1Pairs=${chain.plannedWave1Pairs.length}; liveWave1Pairs=${chain.recordedWave1Pairs.length}; next=${chain.nextStep}`);
|
|
}
|
|
console.log('');
|
|
console.log('Protocol queue:');
|
|
for (const protocol of protocolQueue) {
|
|
console.log(`- ${protocol.name}: ${protocol.currentState}; stage=${protocol.deploymentStage}`);
|
|
}
|
|
if (blockers.length > 0) {
|
|
console.log('');
|
|
console.log('Active blockers:');
|
|
for (const blocker of blockers) {
|
|
console.log(`- ${blocker}`);
|
|
}
|
|
console.log('');
|
|
console.log('Resolution paths:');
|
|
for (const entry of resolutionMatrix) {
|
|
if (entry.state === 'resolved') continue;
|
|
console.log(`- ${entry.key}: ${entry.exitCriteria}`);
|
|
}
|
|
}
|
|
if (writeExplorerConfig) {
|
|
console.log('');
|
|
console.log(`Wrote: ${explorerConfigPath}`);
|
|
}
|
|
NODE
|