diff --git a/config/chain138-aave-rollout-manifest.example.json b/config/chain138-aave-rollout-manifest.example.json new file mode 100644 index 00000000..4990a2e4 --- /dev/null +++ b/config/chain138-aave-rollout-manifest.example.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Canonical manifest template for the native Chain 138 Aave rollout.", + "chainId": 138, + "network": "Chain 138", + "aave": { + "pool": "", + "poolAddressesProvider": "", + "poolDataProvider": "", + "startBlock": "", + "executorTreasury": "", + "executorOwner": "", + "quotePushReceiverOwner": "" + } +} diff --git a/config/chain138-aave-v3-origin-manifest.example.json b/config/chain138-aave-v3-origin-manifest.example.json new file mode 100644 index 00000000..c16faf2f --- /dev/null +++ b/config/chain138-aave-v3-origin-manifest.example.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Chain 138 native Aave V3 Origin market deployment manifest template.", + "chainId": 138, + "network": "Chain 138", + "contractName": "Chain138AaveV3OriginMarket", + "roles": { + "marketOwner": "", + "poolAdmin": "", + "emergencyAdmin": "" + }, + "flags": { + "l2": false + }, + "marketConfig": { + "marketId": "Chain 138 Aave V3 Market", + "providerId": 138, + "oracleDecimals": 8, + "networkBaseTokenPriceInUsdProxyAggregator": "", + "marketReferenceCurrencyPriceInUsdProxyAggregator": "", + "l2SequencerUptimeFeed": "", + "l2PriceOracleSentinelGracePeriod": 0, + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", + "wrappedNativeToken": "", + "flashLoanPremium": "5000000000000000", + "incentivesProxy": "", + "treasury": "" + } +} diff --git a/config/chain138-gmx-synthetics-manifest.example.json b/config/chain138-gmx-synthetics-manifest.example.json new file mode 100644 index 00000000..1a4be48e --- /dev/null +++ b/config/chain138-gmx-synthetics-manifest.example.json @@ -0,0 +1,86 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Chain 138 native GMX synthetics deployment manifest template.", + "chainId": 138, + "network": "chain138", + "rpcUrl": "http://192.168.11.211:8545", + "explorer": { + "apiUrl": "https://explorer.d-bis.org/api", + "browserUrl": "https://explorer.d-bis.org" + }, + "general": { + "feeReceiver": "", + "holdingAddress": "", + "sequencerUptimeFeed": "0x0000000000000000000000000000000000000000", + "sequencerGraceDuration": 300, + "maxUiFeeFactor": "0", + "maxAutoCancelOrders": 6, + "maxTotalCallbackGasLimitForAutoCancelOrders": 5000000, + "minHandleExecutionErrorGas": 1200000, + "minHandleExecutionErrorGasToForward": 1000000, + "minAdditionalGasForExecution": 1000000, + "refundExecutionFeeGasLimit": 200000, + "depositGasLimit": 2050000, + "withdrawalGasLimit": 1500000, + "shiftGasLimit": 2500000, + "createDepositGasLimit": 5000000, + "createGlvDepositGasLimit": 5000000, + "createWithdrawalGasLimit": 5000000, + "createGlvWithdrawalGasLimit": 5000000, + "singleSwapGasLimit": 1000000, + "increaseOrderGasLimit": 3900000, + "decreaseOrderGasLimit": 3900000, + "swapOrderGasLimit": 3400000, + "glvPerMarketGasLimit": 100000, + "glvDepositGasLimit": 2000000, + "glvWithdrawalGasLimit": 2000000, + "glvShiftGasLimit": 3000000, + "tokenTransferGasLimit": 200000, + "nativeTokenTransferGasLimit": 50000, + "setTraderReferralCodeGasLimit": 200000, + "registerCodeGasLimit": 200000, + "estimatedGasFeeBaseAmount": 600000, + "estimatedGasPerOraclePrice": 250000, + "estimatedGasFeeMultiplierFactor": "1000000000000000000000000000000", + "executionGasFeeBaseAmount": 600000, + "executionGasPerOraclePrice": 250000, + "executionGasFeeMultiplierFactor": "1000000000000000000000000000000", + "requestExpirationTime": 300, + "maxSwapPathLength": 3, + "maxCallbackGasLimit": 2000000, + "minCollateralUsd": "1000000000000000000000000000000", + "minPositionSizeUsd": "1000000000000000000000000000000", + "claimableCollateralTimeDivisor": 3600, + "claimableCollateralDelay": 432000, + "positionFeeReceiverFactor": "0", + "swapFeeReceiverFactor": "0", + "borrowingFeeReceiverFactor": "0", + "liquidationFeeReceiverFactor": "0", + "skipBorrowingFeeForSmallerSide": true, + "maxExecutionFeeMultiplierFactor": "100000000000000000000000000000000", + "oracleProviderMinChangeDelay": 3600, + "configMaxPriceAge": 180, + "gelatoRelayFeeMultiplierFactor": "0", + "gelatoRelayFeeBaseAmount": 0, + "relayFeeAddress": "0x0000000000000000000000000000000000000000", + "maxRelayFeeUsdForSubaccount": "0", + "maxDataLength": 18, + "multichainProviders": {}, + "multichainEndpoints": {}, + "srcChainIds": {}, + "eids": {} + }, + "roles": { + "CONTROLLER": {}, + "ORDER_KEEPER": {}, + "ADL_KEEPER": {}, + "LIQUIDATION_KEEPER": {}, + "MARKET_KEEPER": {}, + "FROZEN_ORDER_KEEPER": {}, + "CONFIG_KEEPER": {}, + "LIMITED_CONFIG_KEEPER": {}, + "TIMELOCK_ADMIN": {} + }, + "tokens": {}, + "markets": [] +} diff --git a/config/chain138-remaining-protocol-surface.json b/config/chain138-remaining-protocol-surface.json new file mode 100644 index 00000000..61506e62 --- /dev/null +++ b/config/chain138-remaining-protocol-surface.json @@ -0,0 +1,76 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Canonical Chain 138 remaining native protocol surface inventory for Aave, GMX, and dYdX.", + "version": "1.0.0", + "updated": "2026-04-15", + "chainId": 138, + "network": "Chain 138", + "protocols": [ + { + "key": "aave", + "status": "source-backed", + "discoveredAddresses": {}, + "sourceSubmodule": "vendor/chain138-protocols/aave-v3-origin", + "discoveryEvidence": [ + "2026-04-15: explorer search /api/v2/search?q=Aave returned items=[]", + "2026-04-15: token-aggregation provider capabilities for chainId=138 did not advertise provider=aave", + "2026-04-15: MEV venue coverage and native-venue-coverage for chainId=138 did not include venue=aave", + "2026-04-15: eth_getLogs scan for Aave PoolAddressesProvider event topics returned no matches from block 0..latest" + ], + "requiredEnv": [ + "CHAIN_138_AAVE_POOL", + "CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER", + "CHAIN_138_AAVE_POOL_DATA_PROVIDER", + "CHAIN_138_AAVE_START_BLOCK", + "CHAIN_138_AAVE_EXECUTOR_TREASURY", + "CHAIN_138_AAVE_EXECUTOR_OWNER", + "CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER" + ], + "deployerScripts": [ + "scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh", + "scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh", + "scripts/deployment/publish-chain138-aave-runtime-from-artifacts.sh" + ], + "verifierScripts": [ + "scripts/verify/check-chain138-remaining-protocol-env.sh", + "scripts/verify/check-chain138-aave-rollout-readiness.sh" + ] + }, + { + "key": "gmx", + "status": "source-backed", + "discoveredAddresses": {}, + "sourceSubmodule": "vendor/chain138-protocols/gmx-synthetics", + "discoveryEvidence": [ + "2026-04-15: explorer search /api/v2/search?q=GMX returned items=[]", + "2026-04-15: token-aggregation provider capabilities for chainId=138 did not advertise provider=gmx", + "2026-04-15: MEV venue coverage and native-venue-coverage for chainId=138 did not include venue=gmx", + "2026-04-15: imported official upstream source submodule gmx-io/gmx-synthetics into vendor/chain138-protocols/gmx-synthetics" + ], + "requiredEnv": [ + "CHAIN_138_GMX_ROUTER", + "CHAIN_138_GMX_EXCHANGE_ROUTER", + "CHAIN_138_GMX_READER", + "CHAIN_138_GMX_ORDER_VAULT", + "CHAIN_138_GMX_DEPOSIT_VAULT", + "CHAIN_138_GMX_WITHDRAWAL_VAULT", + "CHAIN_138_GMX_START_BLOCK" + ] + }, + { + "key": "dydx", + "status": "inventory-only", + "discoveredAddresses": {}, + "discoveryEvidence": [ + "2026-04-15: explorer search /api/v2/search?q=dydx, dYdX, and SoloMargin returned items=[]", + "2026-04-15: token-aggregation provider capabilities for chainId=138 did not advertise provider=dydx", + "2026-04-15: MEV venue coverage and native-venue-coverage for chainId=138 did not include venue=dydx" + ], + "requiredEnv": [ + "CHAIN_138_DYDX_SOLO", + "CHAIN_138_DYDX_DATA_PROVIDER", + "CHAIN_138_DYDX_START_BLOCK" + ] + } + ] +} diff --git a/docs/04-configuration/CHAIN138_AAVE_BLOCKER_REMOVAL_WORKSHEET.md b/docs/04-configuration/CHAIN138_AAVE_BLOCKER_REMOVAL_WORKSHEET.md new file mode 100644 index 00000000..dd300574 --- /dev/null +++ b/docs/04-configuration/CHAIN138_AAVE_BLOCKER_REMOVAL_WORKSHEET.md @@ -0,0 +1,121 @@ +# Chain 138 Aave Blocker Removal Worksheet + +Use this worksheet to remove the remaining native Chain `138` Aave blockers in a controlled order. + +## Goal + +Populate and verify the canonical Chain `138` Aave market addresses and operator values required for: + +- `scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh` +- `scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh` +- `scripts/deployment/publish-chain138-aave-runtime-from-artifacts.sh` + +## Canonical inputs + +Fill these values first: + +- `CHAIN_138_AAVE_POOL` +- `CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER` +- `CHAIN_138_AAVE_POOL_DATA_PROVIDER` +- `CHAIN_138_AAVE_START_BLOCK` +- `CHAIN_138_AAVE_EXECUTOR_TREASURY` +- `CHAIN_138_AAVE_EXECUTOR_OWNER` +- `CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER` + +Use the manifest template: + +- [chain138-aave-rollout-manifest.example.json](/home/intlc/projects/proxmox/config/chain138-aave-rollout-manifest.example.json:1) + +Apply a filled manifest into an env snippet with: + +```bash +bash scripts/deployment/apply-chain138-aave-manifest.sh \ + --manifest config/chain138-aave-rollout-manifest.example.json \ + --write reports/status/chain138_aave_runtime.env +``` + +## Blocker-by-blocker checklist + +### 1. `CHAIN_138_AAVE_POOL` + +- [ ] confirm the native Chain `138` Aave pool contract is deployed +- [ ] confirm bytecode exists on Chain `138` +- [ ] confirm `ADDRESSES_PROVIDER()` is readable +- [ ] confirm `FLASHLOAN_PREMIUM_TOTAL()` is readable +- [ ] record the address in the manifest and runtime env + +### 2. `CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER` + +- [ ] confirm the native Chain `138` Aave `PoolAddressesProvider` is deployed +- [ ] confirm bytecode exists on Chain `138` +- [ ] confirm `pool.ADDRESSES_PROVIDER()` equals this value +- [ ] record the address in the manifest and runtime env + +### 3. `CHAIN_138_AAVE_POOL_DATA_PROVIDER` + +- [ ] confirm the native Chain `138` Aave market data-provider contract is deployed +- [ ] confirm bytecode exists on Chain `138` +- [ ] confirm it belongs to the same market as the Pool and AddressesProvider +- [ ] record the address in the manifest and runtime env + +### 4. `CHAIN_138_AAVE_START_BLOCK` + +- [ ] choose the canonical start block for indexing / discovery +- [ ] verify it is numeric +- [ ] record it in the manifest and runtime env + +### 5. `CHAIN_138_AAVE_EXECUTOR_TREASURY` + +- [ ] decide the treasury address for the Chain `138` Aave-backed execution stack +- [ ] confirm it is a real operator-controlled address +- [ ] record it in the manifest and runtime env + +### 6. `CHAIN_138_AAVE_EXECUTOR_OWNER` + +- [ ] decide the final owner for the execution stack +- [ ] confirm it is the intended operational owner +- [ ] record it in the manifest and runtime env + +### 7. `CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER` + +- [ ] decide the final owner for the `AaveQuotePushFlashReceiver` +- [ ] confirm whether it should match the executor owner or use a separate operator address +- [ ] record it in the manifest and runtime env + +## Verification commands + +Run these after the manifest/env is populated: + +```bash +bash scripts/verify/check-chain138-remaining-protocol-env.sh +bash scripts/verify/check-chain138-aave-rollout-readiness.sh +``` + +## Deployment commands + +Dry-run first: + +```bash +bash scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh --dry-run +bash scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh --dry-run +``` + +Apply once all inputs are real and funded: + +```bash +bash scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh --apply +bash scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh --apply +bash scripts/deployment/publish-chain138-aave-runtime-from-artifacts.sh +``` + +## Completion condition + +The Chain `138` Aave blocker set is removed only when: + +1. all seven canonical inputs are populated +2. the Pool, AddressesProvider, and DataProvider have bytecode on Chain `138` +3. `check-chain138-aave-rollout-readiness.sh` passes +4. the execution stack is deployed +5. the quote-push receiver is deployed +6. runtime publication is complete +7. docs/config/registry reflect the live on-chain values diff --git a/docs/04-configuration/CHAIN138_AAVE_V3_ORIGIN_AND_GMX_SYNTHETICS_SCAFFOLD.md b/docs/04-configuration/CHAIN138_AAVE_V3_ORIGIN_AND_GMX_SYNTHETICS_SCAFFOLD.md new file mode 100644 index 00000000..474ea5a2 --- /dev/null +++ b/docs/04-configuration/CHAIN138_AAVE_V3_ORIGIN_AND_GMX_SYNTHETICS_SCAFFOLD.md @@ -0,0 +1,60 @@ +# Chain 138 Aave V3 Origin and GMX Synthetics Scaffold + +This document records the native deployment scaffold added after importing: + +- `vendor/chain138-protocols/aave-v3-origin` +- `vendor/chain138-protocols/gmx-synthetics` + +## Aave V3 Origin + +Canonical manifest template: + +- [chain138-aave-v3-origin-manifest.example.json](/home/intlc/projects/proxmox/config/chain138-aave-v3-origin-manifest.example.json:1) + +Renderer: + +- [render-chain138-aave-v3-origin-market-input.py](/home/intlc/projects/proxmox/scripts/deployment/render-chain138-aave-v3-origin-market-input.py:1) + +Deploy wrapper: + +- [deploy-chain138-aave-v3-origin-market.sh](/home/intlc/projects/proxmox/scripts/deployment/deploy-chain138-aave-v3-origin-market.sh:1) + +This path generates a custom Chain `138` market-input contract under the imported Aave source tree and runs the upstream Foundry batch deployment script against it. + +Dry-run: + +```bash +bash scripts/deployment/deploy-chain138-aave-v3-origin-market.sh --dry-run +``` + +## GMX Synthetics + +Canonical manifest template: + +- [chain138-gmx-synthetics-manifest.example.json](/home/intlc/projects/proxmox/config/chain138-gmx-synthetics-manifest.example.json:1) + +Overlay renderer: + +- [render-chain138-gmx-synthetics-overlay.py](/home/intlc/projects/proxmox/scripts/deployment/render-chain138-gmx-synthetics-overlay.py:1) + +Prepare helper: + +- [prepare-chain138-gmx-synthetics-overlay.sh](/home/intlc/projects/proxmox/scripts/deployment/prepare-chain138-gmx-synthetics-overlay.sh:1) + +Core deploy wrapper: + +- [deploy-chain138-gmx-synthetics-core.sh](/home/intlc/projects/proxmox/scripts/deployment/deploy-chain138-gmx-synthetics-core.sh:1) + +This path generates a Chain `138` Hardhat overlay config and minimal per-network modules, then runs the upstream GMX synthetics deploy flow against that overlay. + +Dry-run: + +```bash +bash scripts/deployment/deploy-chain138-gmx-synthetics-core.sh --dry-run +``` + +## Current boundary + +These scaffolds make `Aave` and `GMX` deploy-program-backed from this repo. + +They do **not** mean Chain `138` live deployment is complete yet. Real manifests, live token/oracle/role inputs, and funded operator accounts are still required before an apply run can be truthful. diff --git a/docs/04-configuration/CHAIN138_BLOCKSCOUT_DODO_INSERT_AND_ROUTE_LINEAGE_REPORT.md b/docs/04-configuration/CHAIN138_BLOCKSCOUT_DODO_INSERT_AND_ROUTE_LINEAGE_REPORT.md new file mode 100644 index 00000000..774a6acd --- /dev/null +++ b/docs/04-configuration/CHAIN138_BLOCKSCOUT_DODO_INSERT_AND_ROUTE_LINEAGE_REPORT.md @@ -0,0 +1,96 @@ +## Chain 138 Blockscout DODO Insert and Route Lineage Report + +Date: 2026-04-16 + +### Summary + +- The live Chain 138 route execution stack is traced to the `DeployEnhancedSwapRouterV2.s.sol` broadcast lineage. +- The deployed `DodoRouteExecutorAdapter` does not match the current local Foundry artifact runtime bytecode. +- `D3MMFactory` and `D3Proxy` both reach the Blockscout verifier successfully, but still fail during `smart_contracts` materialization. + +### Route execution lineage + +The following live contracts and creation transactions are present in: + +- `smom-dbis-138/broadcast/DeployEnhancedSwapRouterV2.s.sol/138/run-latest.json` +- `smom-dbis-138/broadcast/DeployEnhancedSwapRouterV2.s.sol/138/run-1775195187069.json` + +Recovered live lineage: + +- `EnhancedSwapRouterV2` + - address: `0xf1c93f54a5c2fc0d7766ccb0ad8f157dfb4c99ce` + - create tx: `0x30e68f519243377006e93dd82823305729a1ede5f03e744e27e5d57c7b6766a7` +- `IntentBridgeCoordinatorV2` + - address: `0x7d0022b7e8360172fd9c0bb6778113b7ea3674e7` + - create tx: `0x73fc5f883eda73370e3a4f0d800453e095cee07ef5f37793ed4576f47b4fa5fb` +- `DodoRouteExecutorAdapter` + - address: `0x88495b3dccea93b0633390fde71992683121fa62` + - create tx: `0xc574dde65e90421ed1ff5600c1f9dd71a6b8afb5a1b8416b1dde38bd2961120c` +- `DodoV3RouteExecutorAdapter` + - address: `0x9cb97add29c52e3b81989bca2e33d46074b530ef` + - create tx: `0x7c8b4d9a43913c5b97bd2e348282d85987b342377809158ec06c6c47e7e6349c` +- `UniswapV3RouteExecutorAdapter` + - address: `0x960d6db4e78705f82995690548556fb2266308ea` + - create tx: `0xcd82bcb291f7ef36319059081d642a2c7ff1efeff160ba1f077a98ee4d17483d` +- `BalancerRouteExecutorAdapter` + - address: `0x4e1b71b69188ab45021c797039b4887a4924157a` + - create tx: `0xbe2923798c55d562d1097bfa4e861c38e825357fcc34e9b95a6344a5ba0423b7` + +### Route artifact drift + +The local verification path now checks the Foundry `deployedBytecode.object` hash against the live Chain 138 runtime bytecode before submitting. + +Current canary: + +- contract: `DodoRouteExecutorAdapter` +- local artifact keccak: + - `0xd908d26eef16d34c45f16d1584f2ae7c74535c8352d4be011520c0a09b892301` +- on-chain runtime keccak: + - `0x2c2bd22d9b8734935aee04d86664b72e5160cc8ddddef6ea4b50667d3095b90b` + +Conclusion: + +- the route-stack verification blocker is currently a real deployed-source or build-profile drift, not Blockscout transport plumbing + +### DODO verifier / materialization path + +Observed behavior for: + +- `D3MMFactory` `0x78470c7d2925b6738544e2dd4fe7c07cca21ac31` +- `D3Proxy` `0xc9a11abb7c63d88546be24d58a6d95e3762cb843` + +Current live path: + +1. Blockscout accepts the `standard-input` verification request. +2. `smart-contract-verifier` receives the request. +3. Blockscout logs `Solidity standard-json verifier result ... {:ok, ...}`. +4. Blockscout logs: + - `create_or_update_smart_contract ... existing=nil incoming_partially_verified=true ...` + - `create_smart_contract transaction result ... {:error, :smart_contract, #Ecto.Changeset<...>}` +5. The contract still does not materialize into `smart_contracts`. + +Current explorer-side status: + +- public explorer API still returns: + - `name: null` + - `compiler_version: null` + - `is_partially_verified: null` + +### Source instrumentation state + +The live `v7.0.2` Blockscout source tree on CT `5000` contains: + +- `create_smart_contract changeset errors address=... errors=... constraints=...` +- `changeset/2` defaulting missing `language` to `:solidity` + +The remaining live task is to get a rebuilt runtime image that definitely contains that patched branch, then resubmit `D3MMFactory` and `D3Proxy` and read the parsed changeset errors from the Blockscout logs. + +### Remaining work + +1. Finish the in-progress no-cache rebuild of `blockscout/blockscout:chain138-patched-v7`. +2. Restart CT `5000` Blockscout on the rebuilt image. +3. Resubmit: + - `D3MMFactory` + - `D3Proxy` +4. Capture the parsed `changeset` errors from the new `create_smart_contract changeset errors ...` log line. +5. For the route stack, recover the exact historical source/build profile that produced the currently deployed bytecode before re-verifying. diff --git a/docs/04-configuration/CHAIN138_DEPLOYED_SMART_CONTRACT_VERIFICATION_STATUS.md b/docs/04-configuration/CHAIN138_DEPLOYED_SMART_CONTRACT_VERIFICATION_STATUS.md new file mode 100644 index 00000000..983772d6 --- /dev/null +++ b/docs/04-configuration/CHAIN138_DEPLOYED_SMART_CONTRACT_VERIFICATION_STATUS.md @@ -0,0 +1,48 @@ +# Chain 138 Deployed Smart Contract Verification Status + +This report is generated from the canonical Chain `138` inventory in `config/smart-contracts-master.json`, on-chain bytecode checks against the Core RPC, and Blockscout smart-contract metadata from the internal explorer API. + +## Summary + +| Group | Total | Deployed | Verified | Bytecode only | Pending | +| --- | ---: | ---: | ---: | ---: | ---: | +| `dodo_v3_core` | 6 | 6 | 4 | 2 | 0 | +| `flash_infra` | 3 | 3 | 0 | 3 | 0 | +| `native_v2` | 4 | 4 | 4 | 0 | 0 | +| `route_execution_stack` | 12 | 12 | 0 | 12 | 0 | + +## Inventory + +| Group | Label | Address | Deployed | Verification | Blockscout name | Compiler | +| --- | --- | --- | --- | --- | --- | --- | +| `dodo_v3_core` | `D3Oracle` | `0xD7459aEa8bB53C83a1e90262777D730539A326F0` | yes | `verified` | `D3Oracle` | `v0.8.16+commit.07a7930e` | +| `dodo_v3_core` | `D3Vault` | `0x42b6867260Fb9eE6d09B7E0233A1fAD65D0133D1` | yes | `verified` | `D3Vault` | `v0.8.16+commit.07a7930e` | +| `dodo_v3_core` | `DODOApprove` | `0xbF8D5CB7E8F333CA686a27374Ae06F5dfd772E9E` | yes | `verified` | `DODOApprove` | `v0.8.16+commit.07a7930e` | +| `dodo_v3_core` | `DODOApproveProxy` | `0x08d764c03C42635d8ef9046752b5694243E21Fe9` | yes | `verified` | `DODOApproveProxy` | `v0.8.16+commit.07a7930e` | +| `dodo_v3_core` | `D3MMFactory` | `0x78470C7d2925B6738544E2DD4FE7c07CcA21AC31` | yes | `bytecode-only` | `` | `` | +| `dodo_v3_core` | `D3Proxy` | `0xc9a11abB7C63d88546Be24D58a6d95e3762cB843` | yes | `bytecode-only` | `` | `` | +| `flash_infra` | `UniversalCCIPFlashBridgeAdapter` | `0xBe9e0B2d4cF6A3b2994d6f2f0904D2B165eB8ffC` | yes | `bytecode-only` | `` | `` | +| `flash_infra` | `CrossChainFlashRepayReceiver` | `0xD084b68cB4B1ef2cBA09CF99FB1B6552fd9b4859` | yes | `bytecode-only` | `` | `` | +| `flash_infra` | `CrossChainFlashVaultCreditReceiver` | `0x89F7a1fcbBe104BeE96Da4b4b6b7d3AF85f7E661` | yes | `bytecode-only` | `` | `` | +| `native_v2` | `UniswapV2Factory` | `0x0C30F6e67Ab3667fCc2f5CEA8e274ef1FB920279` | yes | `verified` | `UniswapV2Factory` | `v0.5.16+commit.9c3226ce` | +| `native_v2` | `UniswapV2Router` | `0x3019A7fDc76ba7F64F18d78e66842760037ee638` | yes | `verified` | `UniswapV2Router02` | `v0.6.6+commit.6c089d02` | +| `native_v2` | `SushiSwapFactory` | `0x2871207ff0d56089D70c0134d33f1291B6Fce0BE` | yes | `verified` | `UniswapV2Factory` | `v0.6.12+commit.27d51765` | +| `native_v2` | `SushiSwapRouter` | `0xB37b93D38559f53b62ab020A14919f2630a1aE34` | yes | `verified` | `UniswapV2Router02` | `v0.6.12+commit.27d51765` | +| `route_execution_stack` | `EnhancedSwapRouterV2` | `0xF1c93F54A5C2fc0d7766Ccb0Ad8f157DFB4C99Ce` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `IntentBridgeCoordinatorV2` | `0x7D0022B7e8360172fd9C0bB6778113b7Ea3674E7` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `DodoRouteExecutorAdapter` | `0x88495B3dccEA93b0633390fDE71992683121Fa62` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `DodoV3RouteExecutorAdapter` | `0x9Cb97adD29c52e3B81989BcA2E33D46074B530eF` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `UniswapV3RouteExecutorAdapter` | `0x960D6db4E78705f82995690548556fb2266308EA` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `BalancerRouteExecutorAdapter` | `0x4E1B71B69188Ab45021c797039b4887a4924157A` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `CurveRouteExecutorAdapter` | `0x5f0E07071c41ACcD2A1b1032D3bd49b323b9ADE6` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `OneInchRouteExecutorAdapter` | `0x8168083d29b3293F215392A49D16e7FeF4a02600` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `PilotUniswapV3Router` | `0xD164D9cCfAcf5D9F91698f296aE0cd245D964384` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `PilotBalancerVault` | `0x96423d7C1727698D8a25EbFB88131e9422d1a3C3` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `PilotCurve3Pool` | `0xE440Ec15805BE4C7BabCD17A63B8C8A08a492e0f` | yes | `bytecode-only` | `` | `` | +| `route_execution_stack` | `PilotOneInchRouter` | `0x500B84b1Bc6F59C1898a5Fe538eA20A758757A4F` | yes | `bytecode-only` | `` | `` | + +## Notes + +- `verified` means Blockscout currently exposes both a contract name and compiler version. +- `bytecode-only` means the address is known to the explorer, but source metadata has not materialized yet. +- `pending` means the contract is deployed in the canonical inventory, but the current Blockscout API response does not yet expose verification metadata. diff --git a/docs/04-configuration/CHAIN138_EXTERNAL_LISTINGS_AND_REMAINING_FIXES.md b/docs/04-configuration/CHAIN138_EXTERNAL_LISTINGS_AND_REMAINING_FIXES.md new file mode 100644 index 00000000..0a301ae7 --- /dev/null +++ b/docs/04-configuration/CHAIN138_EXTERNAL_LISTINGS_AND_REMAINING_FIXES.md @@ -0,0 +1,119 @@ +# Chain 138 — remaining fixes and external listings + +**Purpose:** One place for (1) **in-repo / operator fixes** that improve pricing and wallet UX without waiting on third parties, and (2) **everything needed to get native fiat** (MetaMask, Trust, etc.) via **external listings**. + +**Canonical token addresses (submission must match):** [EXPLORER_TOKEN_LIST_CROSSCHECK.md](../11-references/EXPLORER_TOKEN_LIST_CROSSCHECK.md) section 5. + +--- + +## 1. Already done (on-chain + developer tooling) + +| Item | Where | +|------|--------| +| Reserve + D3 WETH path (mock, non-stale quotes) | `scripts/deployment/fix-chain138-pricing-feeds.sh` — see [CHAIN138_PRICING_FEEDS_LIVE.md](CHAIN138_PRICING_FEEDS_LIVE.md) | +| D3 verifier default WETH source | `scripts/verify/check-dodo-v3-chain138.sh` | +| dApp USD hints (ETH + stables including mirror **USDT/USDC**) | `metamask-integration/provider/oracles.js` — `getEthUsdPrice`, `getAssetUsdPrice` | +| CoinGecko submission package token table | [coingecko/COINGECKO_SUBMISSION_PACKAGE.md](coingecko/COINGECKO_SUBMISSION_PACKAGE.md) — **aligned to** [EXPLORER_TOKEN_LIST_CROSSCHECK.md](../11-references/EXPLORER_TOKEN_LIST_CROSSCHECK.md) **§5** (includes **cUSDT/cUSDC V2**, mirror **USDT/USDC** for forms; full set in §5) | + +--- + +## 2. Additional fixes (recommended, no listing required) + +These improve **correctness**, **ops**, or **dApp** UX; they do **not** by themselves fill MetaMask’s native fiat column on chain 138. + +| Priority | Action | Why | +|----------|--------|-----| +| High | Keep **`smom-dbis-138/scripts/reserve/sync-weth-mock-price.sh`** on schedule (e.g. `pmm-mesh-6s-automation.sh`) | `OraclePriceFeed` rejects aggregator reads when `updatedAt` is older than `updateInterval * 2` (~60s with default 30s interval). | +| High | Run **`PriceFeedKeeper.performUpkeep`** (systemd `keeper-service.js` or mesh script) with **`KEEPER_PRIVATE_KEY`** and **`PRICE_FEED_KEEPER_ADDRESS`** | Pushes tracked assets (now includes **WETH10**) into `ReserveSystem` on cadence. | +| Medium | **`pnpm run verify:token-aggregation-api`** or LAN push scripts if report routes break | CoinGecko/CMC submissions and Snaps depend on report JSON and `/api/config/token-list`. Runbook: [TOKEN_AGGREGATION_REPORT_API_RUNBOOK.md](TOKEN_AGGREGATION_REPORT_API_RUNBOOK.md). | +| Medium | **Blockscout WETH9 metadata** (`name`/`symbol`/`decimals` null or 0 on `/api/v2/tokens`) | Wallets and indexers read Explorer; see [EXPLORER_TOKEN_LIST_CROSSCHECK.md](../11-references/EXPLORER_TOKEN_LIST_CROSSCHECK.md) §2.1 — fix contract metadata or Blockscout re-index / override. | +| Low | Re-run **`bash scripts/verify/check-chain138-rpc-health.sh`** after infra changes | Head spread and public RPC sanity. | +| Low | Ensure token-aggregation **`.env`** sets **`USDT_ADDRESS_138`**, **`USDC_ADDRESS_138`** (or `OFFICIAL_USDT_ADDRESS` / `OFFICIAL_USDC_ADDRESS`) so `report/coingecko?chainId=138` matches mirror **USDT/USDC** used on-chain; optional schema fields for `coingecko_id` when platforms support chain **138** | Avoids export vs wallet-address drift (see `canonical-tokens.ts` Chain **138** USDT/USDC resolution). | + +--- + +## 3. External listings — what each integration needs + +### Listing scope: `c*` on Chain 138 vs `cW*` on host chains + +**No — not automatically.** CoinGecko, CMC, and MetaMask-style price backends index **(chain ID, contract address)**. The materials in [COINGECKO_SUBMISSION_PACKAGE.md](coingecko/COINGECKO_SUBMISSION_PACKAGE.md) and the **Chain 138** export `?chainId=138` cover **GRU base money and mirrors on chain 138** (`cUSDT`, `cUSDC`, mirror **USDT/USDC**, WETH variants, etc.), not the **mesh `cW*`** tokens deployed on **other networks**. + +**`cW*`** (public PMM / corridor capacity on Ethereum, Polygon, Arbitrum, …) live at **different chain IDs** — see [deployment-status.json](../../cross-chain-pmm-lps/config/deployment-status.json) (`chains."1".cwTokens`, and other `chains.*` entries). Each contract needs its **own** listing row under the **correct host chain** (e.g. Ethereum **1** for most `cWUSDT` / `cWUSDC` / `cWEURC` …). + +**Token-aggregation exports for host chains:** `GET /api/v1/report/coingecko?chainId=1` (and other supported IDs in `smom-dbis-138/services/token-aggregation/src/config/chains.ts`) **only includes tokens that have non-empty canonical addresses for that `chainId`** and meaningful rows if the indexer has **`CHAIN_1_RPC_URL` / `ETHEREUM_MAINNET_RPC`** (or the matching `CHAIN_*_RPC_URL`) and DB coverage. If the export is empty, use `deployment-status.json` plus manual forms until indexing is wired — same URL pattern as [CMC_COINGECKO_SUBMISSION_RUNBOOK.md](coingecko/CMC_COINGECKO_SUBMISSION_RUNBOOK.md) §2.1, **per chain**. + +**Policy context:** `cW*` is the **execution / mesh** layer; `c*` on 138 is **reference-aligned base money** — [GRU_REFERENCE_PRIMACY_AND_MESH_EXECUTION_MODEL.md](GRU_REFERENCE_PRIMACY_AND_MESH_EXECUTION_MODEL.md). Listings are still **per-chain contracts** for wallet price UIs. + +### 3.1 CoinGecko (highest impact for MetaMask-style fiat) + +**Goal:** Chain **138** and each **contract** indexed so price APIs return USD. + +| You need | Detail | +|----------|--------| +| **Account** | CoinGecko user; use [request / new coin](https://www.coingecko.com/en/request) flows per [COINGECKO_SUBMISSION_GUIDE](coingecko/COINGECKO_SUBMISSION_GUIDE.md). | +| **Chain row** | Name (e.g. DeFi Oracle Meta Mainnet), **chainId 138**, RPCs, explorer `https://explorer.d-bis.org`, website, consensus note (Besu / QBFT if asked). Package: [COINGECKO_SUBMISSION_PACKAGE.md](coingecko/COINGECKO_SUBMISSION_PACKAGE.md). | +| **Per-token rows** | **Exact** contract, symbol, name, **decimals** from §5; **512×512 PNG** logo per token. | +| **Mirror stables** | Submit **USDT** `0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1` and **USDC** `0x71D6687F38b93CCad569Fa6352c876eea967201b` if users hold those symbols — they are **not** the same contract as cUSDT/cUSDC. | +| **Machine-readable export** | `GET …/api/v1/report/coingecko?chainId=138` — see [CMC_COINGECKO_SUBMISSION_RUNBOOK.md](coingecko/CMC_COINGECKO_SUBMISSION_RUNBOOK.md) §2.1. | +| **If CG rejects “unsupported chain”** | Keep exports current; resubmit when they add chain **138** — no code blocker. | + +### 3.2 CoinMarketCap (CMC) + +| You need | Detail | +|----------|--------| +| **Export** | `GET …/api/v1/report/cmc?chainId=138` — pairs, liquidity, volume fields per [CMC_COINGECKO_REPORTING.md](../../smom-dbis-138/services/token-aggregation/docs/CMC_COINGECKO_REPORTING.md). | +| **Same assets as CoinGecko** | Logos 512×512, canonical addresses, honest liquidity/volume from your indexer. | +| **Process** | CMC’s own listing / DEX form (changes over time) — [CMC_COINGECKO_SUBMISSION_RUNBOOK.md](coingecko/CMC_COINGECKO_SUBMISSION_RUNBOOK.md) §2.3. | + +### 3.3 MetaMask / Consensys (native portfolio fiat) + +MetaMask’s **in-wallet** fiat still comes from **their** price pipeline, not your RPC. + +| You need | Detail | +|----------|--------| +| **Evidence pack** | Chain ID **138**, public RPCs, explorer, **token list URL** `https://explorer.d-bis.org/api/config/token-list`, user count / TVL / partners if available. | +| **Contact** | [Consensys contact](https://consensys.io/contact/), **business@consensys.io**; support / dev portals per [REPOSITORIES_AND_PRS_CHAIN138.md](../00-meta/REPOSITORIES_AND_PRS_CHAIN138.md) §4. | +| **Expectation** | No public “merge PR for chain 138 price” repo; **outreach + listings** (CoinGecko/CMC) together move outcomes faster. | + +### 3.4 Trust Wallet + +| You need | Detail | +|----------|--------| +| **wallet-core PR** | Registry + codegen — [ADD_CHAIN138_TO_TRUST_WALLET.md](ADD_CHAIN138_TO_TRUST_WALLET.md), [pr-ready/trust-wallet-registry-chain138.json](pr-ready/trust-wallet-registry-chain138.json). | +| **Assets logos (optional)** | [assets.trustwallet.com](https://assets.trustwallet.com) for chain **138** tokens. | + +### 3.5 Ledger Live + +| You need | Detail | +|----------|--------| +| **Wait for Ledger** | Form submitted; do not PR upstream until they respond — [REPOSITORIES_AND_PRS_CHAIN138.md](../00-meta/REPOSITORIES_AND_PRS_CHAIN138.md) §1. | + +### 3.6 Chain metadata (ethereum-lists / Chainlist) + +| You need | Detail | +|----------|--------| +| **Maintenance** | Chain **138** is already on [chainlist.org/chain/138](https://chainlist.org/chain/138). For RPC/explorer updates, fork [ethereum-lists/chains](https://github.com/ethereum-lists/chains), edit `_data/chains/eip155-138.json`, PR — [REPOSITORIES_AND_PRS_CHAIN138.md](../00-meta/REPOSITORIES_AND_PRS_CHAIN138.md) §3. | + +--- + +## 4. After a successful listing (repo hygiene) + +When CoinGecko / CMC / a wallet lists you, update status so operators do not duplicate work: + +| Document | What to change | +|----------|----------------| +| [CMC_COINGECKO_SUBMISSION_RUNBOOK.md](coingecko/CMC_COINGECKO_SUBMISSION_RUNBOOK.md) | §4 “When done — where to update” | +| [PLACEHOLDERS_AND_TBD.md](../PLACEHOLDERS_AND_TBD.md) (`docs/PLACEHOLDERS_AND_TBD.md`) | CMC / CoinGecko section — submission or “Listed” dates | +| [REMAINING_COMPONENTS_TASKS_AND_RECOMMENDATIONS.md](../00-meta/REMAINING_COMPONENTS_TASKS_AND_RECOMMENDATIONS.md) | §1.4 task 25 (if present) | +| [PRICE_FEED_CHAIN138_METAMASK_AND_WALLETS.md](PRICE_FEED_CHAIN138_METAMASK_AND_WALLETS.md) | §1 “Current state” table — reflect new wallet behaviour | + +--- + +## 5. See also + +- [PRICE_FEED_CHAIN138_METAMASK_AND_WALLETS.md](PRICE_FEED_CHAIN138_METAMASK_AND_WALLETS.md) — wallet behaviour and checklist +- [CHAIN138_PRICING_FEEDS_LIVE.md](CHAIN138_PRICING_FEEDS_LIVE.md) — on-chain feed matrix +- [COINGECKO_SUBMISSION_PACKAGE.md](coingecko/COINGECKO_SUBMISSION_PACKAGE.md) — chain + token copy-paste +- [TOKEN_AGGREGATION_REPORT_API_RUNBOOK.md](TOKEN_AGGREGATION_REPORT_API_RUNBOOK.md) — report API reachability +- [GRU_V2_PUBLIC_PROTOCOL_DEPLOYMENT_STATUS.md](../11-references/GRU_V2_PUBLIC_PROTOCOL_DEPLOYMENT_STATUS.md) — links `deployment-status.json` and mesh scope +- `metamask-integration/provider/oracles.js` — `getAssetUsdPrice` / `getEthUsdPrice` for dApp USD hints (not MetaMask native column) diff --git a/docs/04-configuration/CHAIN138_NATIVE_PROTOCOL_STACK_GAP_REPORT.md b/docs/04-configuration/CHAIN138_NATIVE_PROTOCOL_STACK_GAP_REPORT.md new file mode 100644 index 00000000..c83ed661 --- /dev/null +++ b/docs/04-configuration/CHAIN138_NATIVE_PROTOCOL_STACK_GAP_REPORT.md @@ -0,0 +1,77 @@ +# Chain 138 Native Protocol Stack Gap Report + +This report answers a specific deployment question: + +If the remaining native Chain `138` protocols do not already exist on-chain, can they be deployed directly from this repo? + +## Answer + +Not fully. + +The repo contains: + +- a Chain `138` Aave-backed execution wrapper deploy path +- a Chain `138` Aave quote-push receiver deploy path +- canonical inventory and readiness checks for `Aave`, `GMX`, and `dYdX` +- imported upstream protocol source repos: + - `vendor/chain138-protocols/aave-v3-origin` + - `vendor/chain138-protocols/gmx-synthetics` + +The repo still does **not** contain a completed Chain `138` deployment program or published live addresses for: + +- an Aave V3 market on Chain `138` +- a GMX synthetics market on Chain `138` +- any dYdX market on Chain `138` + +## Why this matters + +The current Aave scripts still require an already-existing native Aave market: + +- `CHAIN_138_AAVE_POOL` +- `CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER` +- `CHAIN_138_AAVE_POOL_DATA_PROVIDER` + +Those are not “addresses we forgot to copy.” They are the addresses of the native protocol program itself. + +If that market does not yet exist on Chain `138`, then the remaining work is not just runtime config. It is a native protocol deployment project built from the imported upstream source. + +## Audited gap + +Use: + +```bash +bash scripts/verify/check-chain138-native-protocol-stack-source.sh +``` + +This audit checks whether the repo contains the upstream source families expected for native deployments: + +- Aave: + - `PoolAddressesProvider` + - `Pool` + - `PoolConfigurator` + - `PoolDataProvider` + - `AaveOracle` +- GMX: + - `Router` + - `Vault` + - `PositionRouter` + - `Reader` +- dYdX: + - `SoloMargin` + - `DataProvider` + +If those source families are present, that proves upstream source has been imported. It does not, by itself, mean Chain `138` deployment is complete. + +## Practical implication + +To finish native Chain `138` rollout for the remaining protocols, one of these must happen: + +1. use the imported upstream source repos to build a real Chain `138` deployment program +2. deploy the native protocol stack on Chain `138` +3. publish canonical live Chain `138` addresses and runtime config + +Until that happens: + +- `Aave` remains `blocked`, `source-backed` +- `GMX` remains `blocked`, `source-backed` +- `dYdX` remains `blocked`, `inventory-backed` diff --git a/docs/04-configuration/CHAIN138_PRICING_FEEDS_LIVE.md b/docs/04-configuration/CHAIN138_PRICING_FEEDS_LIVE.md new file mode 100644 index 00000000..315b0f74 --- /dev/null +++ b/docs/04-configuration/CHAIN138_PRICING_FEEDS_LIVE.md @@ -0,0 +1,51 @@ +# Chain 138 — live pricing feeds (operator reference) + +**Purpose:** Single table of on-chain pricing surfaces after the Reserve + D3 + keeper alignment (`fix-chain138-pricing-feeds.sh`). + +**Repair (LAN + `PRIVATE_KEY`):** + +```bash +./scripts/deployment/fix-chain138-pricing-feeds.sh --dry-run +./scripts/deployment/fix-chain138-pricing-feeds.sh --apply +``` + +Keep **`sync-weth-mock-price.sh`** on a schedule (see `smom-dbis-138/scripts/reserve/pmm-mesh-6s-automation.sh`) so the WETH mock `updatedAt` stays inside `OraclePriceFeed`’s freshness window. + +--- + +## 1. Feed matrix (Chain 138) + +| Role | Asset / pair | Contract | Notes | +|------|----------------|----------|--------| +| **WETH spot (8 dp)** | ETH/USD | `0x3e8725b8De386feF3eFE5678c92eA6aDB41992B2` | **MockPriceFeed**; owner updates from CoinGecko/Binance (`sync-weth-mock-price.sh`). Used by **OraclePriceFeed** (WETH10) and **D3Oracle** WETH10 source to avoid managed-aggregator staleness on Besu. | +| **Managed ETH/USD (legacy)** | ETH/USD | `0x99b3511a2d315a497c8112c1fdd8d508d4b1e506` | Chainlink-style; can report **stale** if not pushed; D3 verifier default is now the mock unless `CHAIN138_D3_WETH_USD_FEED` overrides. | +| **Oracle proxy (legacy)** | ETH/USD | `0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6` | Do **not** rely on `latestRoundData()` for live reads; prefer mock above. | +| **Reserve path** | WETH10 | `OraclePriceFeed` `0x8918eE0819fD687f4eb3e8b9B7D0ef7557493cfa` → `ReserveSystem` `0x607e97cD626f209facfE48c1464815DDE15B5093` | `getPrice(WETH10)` should return 18-decimal USD after `setAggregator` + `updatePriceFeed`. | +| **Reserve path** | cUSDT / cUSDC | Same `OraclePriceFeed` / `ReserveSystem` | Peg read `$1` (18 dp internal). | +| **D3Oracle** | WETH10 source | `D3Oracle` `0xD7459aEa8bB53C83a1e90262777D730539A326F0` | `priceSources(WETH10)` should list the mock after repair. | +| **D3 stables** | USDT, USDC, cUSDT, cUSDC | Managed feeds (see `scripts/verify/check-dodo-v3-chain138.sh` defaults) | `$1.00` answers in probes. | +| **Keeper** | Tracked assets | `PriceFeedKeeper` `0xD3AD6831aacB5386B8A25BB8D8176a6C8a026f04` | WETH10 tracked for mesh upkeep alongside legacy WETH9 if present. | + +--- + +## 2. Verification + +```bash +bash scripts/verify/check-dodo-v3-chain138.sh +cast call --rpc-url "${RPC_URL_138:-http://192.168.11.211:8545}" \ + 0x607e97cD626f209facfE48c1464815DDE15B5093 \ + "getPrice(address)(uint256,uint256)" \ + 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f +``` + +--- + +## 3. MetaMask native USD column + +MetaMask still **does not** fill fiat values for arbitrary ERC-20s on custom chains from these contracts. That applies to **USDT**, **USDC**, **cUSDT**, and **cUSDC** in the main asset list until the chain (or each token) is covered by MetaMask’s price backend (historically CoinGecko-driven) or you use a dApp/Snap overlay. + +Use: + +- **`metamask-integration/provider`**: `getEthUsdPrice`, `getAssetUsdPrice` — **$1 hints** for cUSDT, cUSDC, **cUSDT V2** (`0x9FBfab33882Efe0038DAa608185718b772EE5660`), **cUSDC V2** (`0x219522c60e83dEe01FC5b0329d6fA8fD84b9D13d`), and mirror **USDT/USDC** (`0x004b…`, `0x71D6…`); **WETH** from on-chain ETH/USD feeds. Same addresses are in [EXPLORER_TOKEN_LIST_CROSSCHECK.md](../11-references/EXPLORER_TOKEN_LIST_CROSSCHECK.md) §5. +- **Token list**: `https://explorer.d-bis.org/api/config/token-list` (icons + discovery; not full fiat). +- **Long term**: CoinGecko / CMC listing — [PRICE_FEED_CHAIN138_METAMASK_AND_WALLETS.md](PRICE_FEED_CHAIN138_METAMASK_AND_WALLETS.md) and the consolidated checklist [CHAIN138_EXTERNAL_LISTINGS_AND_REMAINING_FIXES.md](CHAIN138_EXTERNAL_LISTINGS_AND_REMAINING_FIXES.md). diff --git a/docs/04-configuration/CHAIN138_REMAINING_PROTOCOLS_RUNBOOK.md b/docs/04-configuration/CHAIN138_REMAINING_PROTOCOLS_RUNBOOK.md new file mode 100644 index 00000000..7f7d90da --- /dev/null +++ b/docs/04-configuration/CHAIN138_REMAINING_PROTOCOLS_RUNBOOK.md @@ -0,0 +1,122 @@ +# Chain 138 Remaining Protocols Runbook + +This runbook covers the remaining native protocol programs on Chain `138` after the supported spot/routing stack was completed: + +- `Aave` +- `GMX` +- `dYdX` + +## Current truth + +- `Aave` + - repo-backed deployment surface exists for: + - the Aave-backed MEV execution adapter/wrapper path + - the `AaveQuotePushFlashReceiver` + - native Chain `138` Aave market deployment is **not** yet published in canonical env/registry +- `GMX` + - official upstream `gmx-io/gmx-synthetics` is now vendored as a submodule under: + - `vendor/chain138-protocols/gmx-synthetics` + - completion is now blocked on Chain `138` deployment/configuration work and canonical live addresses, not on missing upstream source +- `dYdX` + - no native Chain `138` contract stack is vendored here + - completion is blocked on live protocol addresses and/or an imported deployment stack + +## Canonical inventory + +Use [chain138-remaining-protocol-surface.json](/home/intlc/projects/proxmox/config/chain138-remaining-protocol-surface.json:1) as the source of truth for required Chain `138` env keys. + +For the Aave blocker-removal sequence, use: + +- [CHAIN138_AAVE_BLOCKER_REMOVAL_WORKSHEET.md](/home/intlc/projects/proxmox/docs/04-configuration/CHAIN138_AAVE_BLOCKER_REMOVAL_WORKSHEET.md:1) +- [chain138-aave-rollout-manifest.example.json](/home/intlc/projects/proxmox/config/chain138-aave-rollout-manifest.example.json:1) + +Verify the current surface with: + +```bash +bash scripts/verify/check-chain138-remaining-protocol-env.sh +``` + +For the Aave-specific preflight once addresses exist: + +```bash +bash scripts/verify/check-chain138-aave-rollout-readiness.sh +``` + +## Aave tasks + +1. Publish real Chain `138` addresses: + - `CHAIN_138_AAVE_POOL` + - `CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER` + - `CHAIN_138_AAVE_POOL_DATA_PROVIDER` + - `CHAIN_138_AAVE_START_BLOCK` +2. Set operator env: + - `CHAIN_138_AAVE_EXECUTOR_TREASURY` + - `CHAIN_138_AAVE_EXECUTOR_OWNER` + - `CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER` + - optionally generate an env snippet first: + +```bash +bash scripts/deployment/apply-chain138-aave-manifest.sh \ + --manifest config/chain138-aave-rollout-manifest.example.json \ + --write reports/status/chain138_aave_runtime.env +``` +3. Dry-run the execution wrapper deploy: + +```bash +bash scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh --dry-run +``` + +4. Dry-run the quote-push receiver deploy: + +```bash +bash scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh --dry-run +``` + +5. When the live market is real and funded, apply: + +```bash +bash scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh --apply +bash scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh --apply +``` + +6. Publish the MEV runtime + receiver outputs: + +```bash +bash scripts/deployment/publish-chain138-aave-runtime-from-artifacts.sh +``` + +7. Publish resulting deployed addresses into canonical env / registry / docs. + +## GMX tasks + +1. Publish canonical Chain `138` addresses: + - `CHAIN_138_GMX_ROUTER` + - `CHAIN_138_GMX_EXCHANGE_ROUTER` + - `CHAIN_138_GMX_READER` + - `CHAIN_138_GMX_ORDER_VAULT` + - `CHAIN_138_GMX_DEPOSIT_VAULT` + - `CHAIN_138_GMX_WITHDRAWAL_VAULT` + - `CHAIN_138_GMX_START_BLOCK` +2. Start from the vendored native source tree: + - `vendor/chain138-protocols/gmx-synthetics` +3. Add discovery, route modeling, and execution support once the live stack exists. + +## dYdX tasks + +1. Publish canonical Chain `138` addresses: + - `CHAIN_138_DYDX_SOLO` + - `CHAIN_138_DYDX_DATA_PROVIDER` + - `CHAIN_138_DYDX_START_BLOCK` +2. Add or vendor a real native Chain `138` dYdX deployment/integration stack. +3. Add discovery, route modeling, and execution support once the live stack exists. + +## Completion rule + +These protocol rows should remain `blocked` until: + +1. live addresses are published +2. bytecode is present on Chain `138` +3. config / docs / registry match reality +4. execution or market checks pass + +Do not close them as `done` before all four are true. diff --git a/docs/04-configuration/CHAIN138_REMAINING_PROTOCOL_DISCOVERY_REPORT.md b/docs/04-configuration/CHAIN138_REMAINING_PROTOCOL_DISCOVERY_REPORT.md new file mode 100644 index 00000000..0234ccf6 --- /dev/null +++ b/docs/04-configuration/CHAIN138_REMAINING_PROTOCOL_DISCOVERY_REPORT.md @@ -0,0 +1,104 @@ +# Chain 138 Remaining Protocol Discovery Report + +**Status date:** 2026-04-15 + +This report records the evidence-gathering pass for native `Aave`, `GMX`, and `dYdX` on Chain `138`. + +## Result + +No canonical or discoverable live addresses were found for: + +- `Aave` +- `GMX` +- `dYdX` + +That means the new Chain `138` remaining-protocol inventory cannot be prefilled with real protocol addresses today. + +## Evidence used + +### 1. Explorer search + +The Chain `138` explorer search API returned empty results for these queries: + +- `Aave` +- `GMX` +- `dydx` +- `dYdX` +- `SoloMargin` +- `PoolAddressesProvider` +- `PoolDataProvider` +- `PositionRouter` + +Observed response shape: + +```json +{"items":[],"next_page_params":null} +``` + +### 2. Token-aggregation provider capabilities + +Live `planner-v2` provider capabilities for `chainId=138` do **not** advertise: + +- `aave` +- `gmx` +- `dydx` + +They do advertise the completed supported stack: + +- `dodo` +- `dodo_v3` +- `uniswap_v3` +- `uniswap_v2` +- `sushiswap` +- `balancer` +- `curve` +- `one_inch` + +### 3. MEV venue coverage + +Live `mev.defi-oracle.io` coverage for `chain_id=138` shows: + +- `curve` +- `dodo_d3mm` +- `dodo_pmm` +- `sushiswap` +- `uniswap_v2` +- `uniswap_v3` + +It does **not** show: + +- `aave` +- `gmx` +- `dydx` + +### 4. Direct Chain 138 log scan for Aave provider events + +A direct `eth_getLogs` scan across blocks `0..latest` on Chain `138` returned no matches for core Aave `PoolAddressesProvider`-style topics: + +- `AddressSet(bytes32,address,bool)` +- `AddressSetAsProxy(bytes32,address,address)` +- `ProxyCreated(bytes32,address,address)` +- `MarketIdSet(string)` +- `PoolUpdated(address)` +- `PoolConfiguratorUpdated(address)` +- `PriceOracleUpdated(address)` +- `ACLManagerUpdated(address)` +- `ACLAdminUpdated(address)` +- `PriceOracleSentinelUpdated(address)` +- `PoolDataProviderUpdated(address)` + +This is strong negative evidence that a canonical Aave V3 provider surface is not live on Chain `138`. + +## Conclusion + +The current blocker is not “we forgot to copy the addresses into env.” + +The current blocker is: + +1. no discoverable canonical live deployment evidence for `Aave`, `GMX`, or `dYdX` on Chain `138` +2. therefore no truthful address inventory to prefill + +## Next action + +- If these protocols truly exist on Chain `138`, publish their canonical addresses and deployment inventory. +- Otherwise, treat them as native protocol rollout projects still pending deployment. diff --git a/scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh b/scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh new file mode 100755 index 00000000..bfa4f753 --- /dev/null +++ b/scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Deploy only the Chain 138 Aave quote-push receiver. +# Default: dry-run. Use --apply to broadcast. +# +# Required env for apply: +# PRIVATE_KEY +# CHAIN_138_AAVE_POOL +# Optional env: +# CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER +# CHAIN138_RPC_URL / RPC_URL_138 + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +SMOM="${PROJECT_ROOT}/smom-dbis-138" + +_qp_private_key="${PRIVATE_KEY-}" +_qp_rpc="${RPC_URL_138:-${CHAIN138_RPC_URL:-}}" +_qp_pool="${CHAIN_138_AAVE_POOL-}" +_qp_owner="${CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER-}" + +# shellcheck disable=SC1091 +source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" 2>/dev/null || true +# shellcheck disable=SC1091 +source "${SMOM}/scripts/load-env.sh" >/dev/null 2>&1 || true + +[[ -n "$_qp_private_key" ]] && export PRIVATE_KEY="$_qp_private_key" +[[ -n "$_qp_rpc" ]] && export RPC_URL_138="$_qp_rpc" +[[ -n "$_qp_pool" ]] && export AAVE_POOL_ADDRESS="$_qp_pool" +[[ -n "$_qp_owner" ]] && export QUOTE_PUSH_RECEIVER_OWNER="$_qp_owner" + +unset _qp_private_key _qp_rpc _qp_pool _qp_owner + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || { + echo "[fail] missing required command: $1" >&2 + exit 1 + } +} + +require_env() { + local name="$1" + if [[ -z "${!name:-}" ]]; then + echo "[fail] missing required env: $name" >&2 + exit 1 + fi +} + +resolved_chain_id() { + if [[ -n "${RPC_URL_138:-}" ]] && command -v cast >/dev/null 2>&1; then + cast chain-id --rpc-url "$RPC_URL_138" 2>/dev/null | awk '{print $1}' + return 0 + fi + echo "138" +} + +pick_latest_receiver() { + local mode="$1" + local chain_id + chain_id="$(resolved_chain_id)" + local latest_json="${SMOM}/broadcast/DeployAaveQuotePushFlashReceiver.s.sol/${chain_id}/run-latest.json" + if [[ "$mode" == "dry-run" ]]; then + latest_json="${SMOM}/broadcast/DeployAaveQuotePushFlashReceiver.s.sol/${chain_id}/dry-run/run-latest.json" + fi + if [[ ! -f "$latest_json" ]] || ! command -v jq >/dev/null 2>&1; then + return 1 + fi + jq -r '.transactions[]? | select(.transactionType == "CREATE" and .contractName == "AaveQuotePushFlashReceiver") | .contractAddress' \ + "$latest_json" | tail -n1 +} + +require_cmd cast +require_cmd forge + +MODE="dry-run" +BROADCAST=() +for arg in "$@"; do + case "$arg" in + --dry-run) MODE="dry-run"; BROADCAST=() ;; + --apply) MODE="apply"; BROADCAST=(--broadcast) ;; + *) + echo "[fail] unknown arg: $arg (use --dry-run or --apply)" >&2 + exit 2 + ;; + esac +done + +require_env PRIVATE_KEY +require_env RPC_URL_138 +require_env AAVE_POOL_ADDRESS + +echo "=== deploy-chain138-aave-quote-push-receiver ($MODE) ===" +echo "rpcUrl=$RPC_URL_138" +echo "aavePool=$AAVE_POOL_ADDRESS" +if [[ -n "${QUOTE_PUSH_RECEIVER_OWNER:-}" ]]; then + echo "receiverOwner=$QUOTE_PUSH_RECEIVER_OWNER" +fi + +( + cd "$SMOM" + forge script script/deploy/DeployAaveQuotePushFlashReceiver.s.sol:DeployAaveQuotePushFlashReceiver \ + --rpc-url "$RPC_URL_138" \ + "${BROADCAST[@]}" \ + -vvvv +) + +receiver_addr="$(pick_latest_receiver "$MODE" || true)" +echo +if [[ "$MODE" == "dry-run" ]]; then + echo "Projected receiver address from this dry-run:" +else + echo "After --apply: copy deployed address into .env:" +fi +echo " CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER=${receiver_addr:-...}" diff --git a/scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh b/scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh new file mode 100755 index 00000000..f15e071a --- /dev/null +++ b/scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Chain 138 wrapper for the generic MEV execution deployer using the +# Aave V3 provider-adapter path. +# +# Default is dry-run. Use --apply to broadcast. +# +# Required env for apply: +# PRIVATE_KEY +# CHAIN_138_AAVE_POOL +# Optional env: +# CHAIN_138_AAVE_EXECUTOR_TREASURY +# CHAIN_138_AAVE_EXECUTOR_OWNER +# CHAIN138_RPC_URL / RPC_URL_138 + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +SMOM_ROOT="$PROJECT_ROOT/smom-dbis-138" + +DRY_RUN=1 +for arg in "$@"; do + case "$arg" in + --apply) DRY_RUN=0 ;; + --dry-run) DRY_RUN=1 ;; + *) + echo "Unknown argument: $arg" >&2 + exit 1 + ;; + esac +done + +if [[ -f "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" ]]; then + # shellcheck disable=SC1091 + source "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" + load_deployment_env --repo-root "$SMOM_ROOT" +fi + +RPC_URL="${RPC_URL_138:-${CHAIN138_RPC_URL:-${RPC_URL:-http://192.168.11.211:8545}}}" +AAVE_POOL="${CHAIN_138_AAVE_POOL:-${AAVE_POOL:-}}" +TREASURY="${CHAIN_138_AAVE_EXECUTOR_TREASURY:-${TREASURY:-}}" +EXECUTOR_OWNER="${CHAIN_138_AAVE_EXECUTOR_OWNER:-${EXECUTOR_OWNER:-}}" +OUTPUT_PATH="${MEV_EXECUTION_DEPLOY_OUTPUT:-$PROJECT_ROOT/reports/status/chain138_aave_execution_deploy_$(date +%Y%m%d_%H%M%S).json}" + +if [[ -z "$AAVE_POOL" ]]; then + echo "Missing CHAIN_138_AAVE_POOL (or AAVE_POOL)." >&2 + exit 1 +fi + +CMD=( + bash "$PROJECT_ROOT/scripts/deployment/deploy-mev-execution-contracts.sh" + --rpc-url "$RPC_URL" + --aave-pool "$AAVE_POOL" + --config "$PROJECT_ROOT/MEV_Bot/mev-platform/config.toml" + --output "$OUTPUT_PATH" +) + +if [[ -n "$TREASURY" ]]; then + CMD+=(--treasury "$TREASURY") +fi +if [[ -n "$EXECUTOR_OWNER" ]]; then + CMD+=(--executor-owner "$EXECUTOR_OWNER") +fi +if (( DRY_RUN )); then + CMD+=(--dry-run) +fi + +echo "=== deploy-chain138-aave-v3-execution-stack ===" +echo "rpcUrl=$RPC_URL" +echo "aavePool=$AAVE_POOL" +[[ -n "$TREASURY" ]] && echo "treasury=$TREASURY" +[[ -n "$EXECUTOR_OWNER" ]] && echo "executorOwner=$EXECUTOR_OWNER" +echo "outputPath=$OUTPUT_PATH" + +"${CMD[@]}" diff --git a/scripts/deployment/deploy-chain138-aave-v3-origin-market.sh b/scripts/deployment/deploy-chain138-aave-v3-origin-market.sh new file mode 100755 index 00000000..fdd44e39 --- /dev/null +++ b/scripts/deployment/deploy-chain138-aave-v3-origin-market.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +AAVE_ROOT="$PROJECT_ROOT/vendor/chain138-protocols/aave-v3-origin" + +MANIFEST="${CHAIN138_AAVE_V3_ORIGIN_MANIFEST:-$PROJECT_ROOT/config/chain138-aave-v3-origin-manifest.example.json}" +GENERATED_SOL="${CHAIN138_AAVE_V3_ORIGIN_GENERATED_SOL:-$AAVE_ROOT/scripts/generated/Chain138AaveV3OriginMarket.sol}" +CONTRACT_NAME="${CHAIN138_AAVE_V3_ORIGIN_CONTRACT_NAME:-Chain138AaveV3OriginMarket}" +RPC_URL="${RPC_URL_138:-${CHAIN138_RPC_URL:-${RPC_URL:-http://192.168.11.211:8545}}}" +MODE="dry-run" + +for arg in "$@"; do + case "$arg" in + --apply) MODE="apply" ;; + --dry-run) MODE="dry-run" ;; + *) echo "Unknown argument: $arg" >&2; exit 1 ;; + esac +done + +command -v python3 >/dev/null 2>&1 || { echo "python3 is required" >&2; exit 1; } +command -v forge >/dev/null 2>&1 || { echo "forge is required" >&2; exit 1; } +[[ -f "$MANIFEST" ]] || { echo "Manifest not found: $MANIFEST" >&2; exit 1; } + +python3 "$PROJECT_ROOT/scripts/deployment/render-chain138-aave-v3-origin-market-input.py" "$MANIFEST" "$GENERATED_SOL" >/dev/null + +echo "=== deploy-chain138-aave-v3-origin-market ($MODE) ===" +echo "manifest=$MANIFEST" +echo "generatedSol=$GENERATED_SOL" +echo "rpcUrl=$RPC_URL" +echo "contract=$CONTRACT_NAME" + +if [[ "$MODE" == "dry-run" ]]; then + echo "forge -C \"$AAVE_ROOT\" script scripts/generated/$(basename "$GENERATED_SOL"):$CONTRACT_NAME --rpc-url \"$RPC_URL\" -vvvv" + exit 0 +fi + +( + cd "$AAVE_ROOT" + forge script "scripts/generated/$(basename "$GENERATED_SOL"):$CONTRACT_NAME" \ + --rpc-url "$RPC_URL" \ + --broadcast \ + -vvvv +) diff --git a/scripts/deployment/deploy-chain138-gmx-synthetics-core.sh b/scripts/deployment/deploy-chain138-gmx-synthetics-core.sh new file mode 100755 index 00000000..f67201de --- /dev/null +++ b/scripts/deployment/deploy-chain138-gmx-synthetics-core.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +GMX_ROOT="$PROJECT_ROOT/vendor/chain138-protocols/gmx-synthetics" +MANIFEST="${CHAIN138_GMX_SYNTHETICS_MANIFEST:-$PROJECT_ROOT/config/chain138-gmx-synthetics-manifest.example.json}" +MODE="dry-run" + +for arg in "$@"; do + case "$arg" in + --apply) MODE="apply" ;; + --dry-run) MODE="dry-run" ;; + *) echo "Unknown argument: $arg" >&2; exit 1 ;; + esac +done + +OUT_DIR="$(bash "$PROJECT_ROOT/scripts/deployment/prepare-chain138-gmx-synthetics-overlay.sh")" +CONFIG_PATH="$OUT_DIR/hardhat.chain138.config.ts" +TAGS="${CHAIN138_GMX_CORE_TAGS:-Router,ExchangeRouter,Reader,OrderVault,DepositVault,WithdrawalVault}" + +echo "=== deploy-chain138-gmx-synthetics-core ($MODE) ===" +echo "manifest=$MANIFEST" +echo "overlay=$OUT_DIR" +echo "tags=$TAGS" + +if [[ "$MODE" == "dry-run" ]]; then + echo "cd \"$GMX_ROOT\" && npx hardhat deploy --config \"$CONFIG_PATH\" --network chain138 --tags \"$TAGS\"" + exit 0 +fi + +( + cd "$GMX_ROOT" + npx hardhat deploy --config "$CONFIG_PATH" --network chain138 --tags "$TAGS" +) diff --git a/scripts/deployment/deploy-chain138-pilot-protocol-venues.sh b/scripts/deployment/deploy-chain138-pilot-protocol-venues.sh new file mode 100755 index 00000000..83436326 --- /dev/null +++ b/scripts/deployment/deploy-chain138-pilot-protocol-venues.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Root-level wrapper for the existing Chain 138 pilot venue deployer covering +# Uniswap v3, Balancer, Curve, and 1inch reference rails. +# +# Default is dry-run. Use --apply to broadcast. +# +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +SMOM_ROOT="$PROJECT_ROOT/smom-dbis-138" + +DRY_RUN=1 +for arg in "$@"; do + case "$arg" in + --apply) DRY_RUN=0 ;; + --dry-run) DRY_RUN=1 ;; + *) + echo "Unknown argument: $arg" >&2 + exit 1 + ;; + esac +done + +if [[ -f "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" ]]; then + # shellcheck disable=SC1091 + source "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" + load_deployment_env --repo-root "$SMOM_ROOT" +fi + +RPC_URL="${RPC_URL_138:-${RPC_URL:-http://192.168.11.211:8545}}" + +CMD=( + forge script + script/bridge/trustless/DeployChain138PilotDexVenues.s.sol:DeployChain138PilotDexVenues + --rpc-url "$RPC_URL" + --chain-id 138 + --legacy + -vvv +) + +if (( DRY_RUN )); then + echo "[DRY-RUN] cd $SMOM_ROOT && ${CMD[*]} --broadcast --private-key \$PRIVATE_KEY" +else + ( + cd "$SMOM_ROOT" + "${CMD[@]}" --broadcast --private-key "$PRIVATE_KEY" + ) +fi diff --git a/scripts/deployment/deploy-chain138-sushiswap-native.sh b/scripts/deployment/deploy-chain138-sushiswap-native.sh new file mode 100755 index 00000000..a70fea5a --- /dev/null +++ b/scripts/deployment/deploy-chain138-sushiswap-native.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +SMOM_ROOT="${PROJECT_ROOT}/smom-dbis-138" + +if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then + # shellcheck source=/dev/null + source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" +fi + +if [[ -f "${SMOM_ROOT}/scripts/lib/deployment/dotenv.sh" ]]; then + # shellcheck source=/dev/null + source "${SMOM_ROOT}/scripts/lib/deployment/dotenv.sh" + load_deployment_env --repo-root "${SMOM_ROOT}" +fi + +if [[ -n "${PRIVATE_KEY:-}" ]]; then + PRIVATE_KEY="$(printf '%s' "${PRIVATE_KEY}" | tr -d '\r\n')" + export PRIVATE_KEY +fi + +DRY_RUN=1 +for arg in "$@"; do + case "$arg" in + --apply) DRY_RUN=0 ;; + --dry-run) DRY_RUN=1 ;; + *) + echo "Unknown argument: ${arg}" >&2 + exit 1 + ;; + esac +done + +CMD=(npx hardhat run scripts/chain138/deploy-sushiswap-native.js --network chain138 --no-compile) + +if (( DRY_RUN )); then + echo "[DRY-RUN] cd ${SMOM_ROOT} && ${CMD[*]}" +else + (cd "${SMOM_ROOT}" && "${CMD[@]}") +fi diff --git a/scripts/deployment/deploy-chain138-uniswap-v2-native.sh b/scripts/deployment/deploy-chain138-uniswap-v2-native.sh new file mode 100755 index 00000000..afc08e21 --- /dev/null +++ b/scripts/deployment/deploy-chain138-uniswap-v2-native.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +SMOM_ROOT="${PROJECT_ROOT}/smom-dbis-138" + +if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then + # shellcheck source=/dev/null + source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" +fi + +if [[ -f "${SMOM_ROOT}/scripts/lib/deployment/dotenv.sh" ]]; then + # shellcheck source=/dev/null + source "${SMOM_ROOT}/scripts/lib/deployment/dotenv.sh" + load_deployment_env --repo-root "${SMOM_ROOT}" +fi + +if [[ -n "${PRIVATE_KEY:-}" ]]; then + PRIVATE_KEY="$(printf '%s' "${PRIVATE_KEY}" | tr -d '\r\n')" + export PRIVATE_KEY +fi + +DRY_RUN=1 +for arg in "$@"; do + case "$arg" in + --apply) DRY_RUN=0 ;; + --dry-run) DRY_RUN=1 ;; + *) + echo "Unknown argument: ${arg}" >&2 + exit 1 + ;; + esac +done + +CMD=(npx hardhat run scripts/chain138/deploy-uniswap-v2-native.js --network chain138 --no-compile) + +if (( DRY_RUN )); then + echo "[DRY-RUN] cd ${SMOM_ROOT} && ${CMD[*]}" +else + (cd "${SMOM_ROOT}" && "${CMD[@]}") +fi diff --git a/scripts/deployment/prepare-chain138-gmx-synthetics-overlay.sh b/scripts/deployment/prepare-chain138-gmx-synthetics-overlay.sh new file mode 100755 index 00000000..12408d5f --- /dev/null +++ b/scripts/deployment/prepare-chain138-gmx-synthetics-overlay.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +MANIFEST="${CHAIN138_GMX_SYNTHETICS_MANIFEST:-$PROJECT_ROOT/config/chain138-gmx-synthetics-manifest.example.json}" +OUT_DIR="${CHAIN138_GMX_SYNTHETICS_RENDER_DIR:-$PROJECT_ROOT/reports/generated/chain138-gmx-synthetics}" + +command -v python3 >/dev/null 2>&1 || { echo "python3 is required" >&2; exit 1; } +[[ -f "$MANIFEST" ]] || { echo "Manifest not found: $MANIFEST" >&2; exit 1; } + +python3 "$PROJECT_ROOT/scripts/deployment/render-chain138-gmx-synthetics-overlay.py" "$MANIFEST" "$OUT_DIR" >/dev/null +echo "$OUT_DIR" diff --git a/scripts/deployment/render-chain138-aave-v3-origin-market-input.py b/scripts/deployment/render-chain138-aave-v3-origin-market-input.py new file mode 100644 index 00000000..7fc4d9e6 --- /dev/null +++ b/scripts/deployment/render-chain138-aave-v3-origin-market-input.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +import json +import pathlib +import sys + + +def solidity_addr(value: str) -> str: + if not value: + return "address(0)" + return value + + +def solidity_bytes32(value: str) -> str: + if not value: + return "bytes32(0)" + return value + + +def main() -> int: + if len(sys.argv) != 3: + print("usage: render-chain138-aave-v3-origin-market-input.py ", file=sys.stderr) + return 1 + + manifest_path = pathlib.Path(sys.argv[1]) + output_path = pathlib.Path(sys.argv[2]) + manifest = json.loads(manifest_path.read_text()) + + name = manifest.get("contractName", "Chain138AaveV3OriginMarket") + roles = manifest["roles"] + flags = manifest["flags"] + config = manifest["marketConfig"] + + content = f"""// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {{DeployAaveV3MarketBatchedBase}} from "../misc/DeployAaveV3MarketBatchedBase.sol"; +import {{MarketInput}} from "../../src/deployments/inputs/MarketInput.sol"; + +contract {name} is DeployAaveV3MarketBatchedBase, MarketInput {{ + function _getMarketInput( + address + ) + internal + pure + override + returns ( + Roles memory roles, + MarketConfig memory config, + DeployFlags memory flags, + MarketReport memory deployedContracts + ) + {{ + roles.marketOwner = {solidity_addr(roles.get("marketOwner", ""))}; + roles.poolAdmin = {solidity_addr(roles.get("poolAdmin", ""))}; + roles.emergencyAdmin = {solidity_addr(roles.get("emergencyAdmin", ""))}; + + config.marketId = "{config.get("marketId", "Chain 138 Aave V3 Market")}"; + config.providerId = {config.get("providerId", 138)}; + config.oracleDecimals = {config.get("oracleDecimals", 8)}; + config.networkBaseTokenPriceInUsdProxyAggregator = {solidity_addr(config.get("networkBaseTokenPriceInUsdProxyAggregator", ""))}; + config.marketReferenceCurrencyPriceInUsdProxyAggregator = {solidity_addr(config.get("marketReferenceCurrencyPriceInUsdProxyAggregator", ""))}; + config.l2SequencerUptimeFeed = {solidity_addr(config.get("l2SequencerUptimeFeed", ""))}; + config.l2PriceOracleSentinelGracePeriod = {config.get("l2PriceOracleSentinelGracePeriod", 0)}; + config.salt = {solidity_bytes32(config.get("salt", ""))}; + config.wrappedNativeToken = {solidity_addr(config.get("wrappedNativeToken", ""))}; + config.flashLoanPremium = {config.get("flashLoanPremium", "5000000000000000")}; + config.incentivesProxy = {solidity_addr(config.get("incentivesProxy", ""))}; + config.treasury = {solidity_addr(config.get("treasury", ""))}; + + flags.l2 = {str(bool(flags.get("l2", False))).lower()}; + + return (roles, config, flags, deployedContracts); + }} +}} +""" + + output_path.parent.mkdir(parents=True, exist_ok=True) + output_path.write_text(content) + print(output_path) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/deployment/render-chain138-gmx-synthetics-overlay.py b/scripts/deployment/render-chain138-gmx-synthetics-overlay.py new file mode 100644 index 00000000..0ec0ff35 --- /dev/null +++ b/scripts/deployment/render-chain138-gmx-synthetics-overlay.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python3 +import json +import pathlib +import sys + + +def ts_value(value): + if isinstance(value, bool): + return "true" if value else "false" + if isinstance(value, (int, float)): + return str(value) + if isinstance(value, str): + return json.dumps(value) + if isinstance(value, list): + return "[" + ", ".join(ts_value(v) for v in value) + "]" + if isinstance(value, dict): + items = [] + for k, v in value.items(): + items.append(f"{json.dumps(k)}: {ts_value(v)}") + return "{\n" + ",\n".join(items) + "\n}" + return "undefined" + + +def write(path: pathlib.Path, content: str): + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content) + + +def main() -> int: + if len(sys.argv) != 3: + print("usage: render-chain138-gmx-synthetics-overlay.py ", file=sys.stderr) + return 1 + manifest = json.loads(pathlib.Path(sys.argv[1]).read_text()) + out_dir = pathlib.Path(sys.argv[2]) + net = manifest["network"] + + write(out_dir / "chain138.tokens.ts", f"""export default async function () {{ + return {ts_value(manifest.get("tokens", {}))}; +}} +""") + write(out_dir / "chain138.markets.ts", f"""export default async function () {{ + return {ts_value(manifest.get("markets", []))}; +}} +""") + write(out_dir / "chain138.general.ts", f"""export default async function () {{ + return {ts_value(manifest.get("general", {}))}; +}} +""") + write(out_dir / "chain138.roles.ts", f"""export default async function () {{ + return {{ + roles: {ts_value(manifest.get("roles", {}))}, + requiredRolesForContracts: {ts_value({ + "CONFIG_KEEPER": ["ConfigSyncer"], + "CONTROLLER": ["Config", "ConfigSyncer", "ConfigTimelockController", "MarketFactory", "ExchangeRouter", "OrderHandler", "DepositHandler", "WithdrawalHandler", "Router", "Reader"], + "ROUTER_PLUGIN": ["ExchangeRouter"], + "ROLE_ADMIN": ["ConfigTimelockController"] + })} + }}; +}} +""") + write(out_dir / "hardhat.chain138.config.ts", f"""import baseConfig from "../../vendor/chain138-protocols/gmx-synthetics/hardhat.config"; +import {{ extendEnvironment }} from "hardhat/config"; +import tokensConfig from "./chain138.tokens"; +import marketsConfig from "./chain138.markets"; +import generalConfig from "./chain138.general"; +import rolesConfig from "./chain138.roles"; + +const config: any = baseConfig; +config.networks = config.networks || {{}}; +config.networks["{net}"] = {{ + url: process.env.CHAIN138_RPC_URL || process.env.RPC_URL_138 || "{manifest.get("rpcUrl", "http://192.168.11.211:8545")}", + chainId: {manifest.get("chainId", 138)}, + accounts: process.env.ACCOUNT_KEY ? [process.env.ACCOUNT_KEY] : [], + blockGasLimit: 20000000 +}}; +config.etherscan = config.etherscan || {{}}; +config.etherscan.customChains = config.etherscan.customChains || []; +config.etherscan.customChains.push({{ + network: "{net}", + chainId: {manifest.get("chainId", 138)}, + urls: {{ + apiURL: "{manifest.get("explorer", {}).get("apiUrl", "https://explorer.d-bis.org/api")}", + browserURL: "{manifest.get("explorer", {}).get("browserUrl", "https://explorer.d-bis.org")}" + }} +}}); + +extendEnvironment(async (hre: any) => {{ + if (hre.network.name !== "{net}") return; + hre.gmx = {{ + getTokens: async () => tokensConfig(), + getMarkets: async () => marketsConfig(), + getGeneral: async () => generalConfig(), + getRoles: async () => rolesConfig(), + getOracle: async () => ({{}}), + getGlvs: async () => ({{}}), + getBuyback: async () => ({{}}), + getRiskOracle: async () => ({{}}), + getVaultV1: async () => ({{}}), + isExistingMainnetDeployment: false, + getLayerZeroEndpoint: async () => undefined, + getFeeDistributor: async () => ({{}}) + }}; +}}); + +export default config; +""") + print(out_dir) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/verify/check-chain138-aave-rollout-readiness.sh b/scripts/verify/check-chain138-aave-rollout-readiness.sh new file mode 100755 index 00000000..8b4f1d72 --- /dev/null +++ b/scripts/verify/check-chain138-aave-rollout-readiness.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +SMOM_ROOT="$PROJECT_ROOT/smom-dbis-138" + +if [[ -f "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" ]]; then + # shellcheck disable=SC1091 + source "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" + load_deployment_env --repo-root "$SMOM_ROOT" +fi + +command -v cast >/dev/null 2>&1 || { echo "cast is required" >&2; exit 1; } + +RPC_URL="${RPC_URL_138:-${CHAIN138_RPC_URL:-${RPC_URL:-http://192.168.11.211:8545}}}" +POOL="${CHAIN_138_AAVE_POOL:-}" +PROVIDER="${CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER:-}" +DATA_PROVIDER="${CHAIN_138_AAVE_POOL_DATA_PROVIDER:-}" +START_BLOCK="${CHAIN_138_AAVE_START_BLOCK:-}" +TREASURY="${CHAIN_138_AAVE_EXECUTOR_TREASURY:-}" +OWNER="${CHAIN_138_AAVE_EXECUTOR_OWNER:-}" +RECEIVER_OWNER="${CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER:-}" + +failures=0 + +require_var() { + local name="$1" value="$2" + if [[ -n "$value" ]]; then + echo "SET $name=$value" + else + echo "MISS $name" + failures=1 + fi +} + +check_code() { + local label="$1" addr="$2" + if [[ ! "$addr" =~ ^0x[0-9a-fA-F]{40}$ ]]; then + echo "BAD $label invalid address: $addr" + failures=1 + return + fi + local code + code="$(cast code "$addr" --rpc-url "$RPC_URL" 2>/dev/null || true)" + if [[ -n "$code" && "$code" != "0x" ]]; then + echo "CODE $label bytecode present" + else + echo "NOCODE $label no bytecode at $addr" + failures=1 + fi +} + +check_eoa_or_contract_address() { + local label="$1" addr="$2" + if [[ "$addr" =~ ^0x[0-9a-fA-F]{40}$ ]] && [[ "${addr,,}" != "0x0000000000000000000000000000000000000000" ]]; then + echo "ADDR $label format ok" + else + echo "BAD $label invalid address: $addr" + failures=1 + fi +} + +echo "=== Chain 138 Aave rollout readiness ===" +echo "rpcUrl=$RPC_URL" + +require_var "CHAIN_138_AAVE_POOL" "$POOL" +require_var "CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER" "$PROVIDER" +require_var "CHAIN_138_AAVE_POOL_DATA_PROVIDER" "$DATA_PROVIDER" +require_var "CHAIN_138_AAVE_START_BLOCK" "$START_BLOCK" +require_var "CHAIN_138_AAVE_EXECUTOR_TREASURY" "$TREASURY" +require_var "CHAIN_138_AAVE_EXECUTOR_OWNER" "$OWNER" +require_var "CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER" "$RECEIVER_OWNER" + +[[ -n "$POOL" ]] && check_code "AAVE_POOL" "$POOL" +[[ -n "$PROVIDER" ]] && check_code "AAVE_POOL_ADDRESSES_PROVIDER" "$PROVIDER" +[[ -n "$DATA_PROVIDER" ]] && check_code "AAVE_POOL_DATA_PROVIDER" "$DATA_PROVIDER" +[[ -n "$TREASURY" ]] && check_eoa_or_contract_address "CHAIN_138_AAVE_EXECUTOR_TREASURY" "$TREASURY" +[[ -n "$OWNER" ]] && check_eoa_or_contract_address "CHAIN_138_AAVE_EXECUTOR_OWNER" "$OWNER" +[[ -n "$RECEIVER_OWNER" ]] && check_eoa_or_contract_address "CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER" "$RECEIVER_OWNER" + +if [[ -n "$START_BLOCK" ]]; then + if [[ "$START_BLOCK" =~ ^[0-9]+$ ]]; then + echo "START_BLOCK numeric" + else + echo "BAD CHAIN_138_AAVE_START_BLOCK invalid numeric value: $START_BLOCK" + failures=1 + fi +fi + +if [[ -n "$POOL" && -n "$PROVIDER" ]]; then + onchain_provider="$(cast call "$POOL" 'ADDRESSES_PROVIDER()(address)' --rpc-url "$RPC_URL" 2>/dev/null | awk '{print $1}' || true)" + if [[ -n "$onchain_provider" ]]; then + echo "POOL_PROVIDER onchain=$onchain_provider" + if [[ "${onchain_provider,,}" != "${PROVIDER,,}" ]]; then + echo "MISMATCH pool.ADDRESSES_PROVIDER() != CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER" + failures=1 + fi + else + echo "WARN unable to read ADDRESSES_PROVIDER() from pool" + failures=1 + fi + + flash_fee="$(cast call "$POOL" 'FLASHLOAN_PREMIUM_TOTAL()(uint128)' --rpc-url "$RPC_URL" 2>/dev/null | awk '{print $1}' || true)" + if [[ -n "$flash_fee" ]]; then + echo "FLASHLOAN_PREMIUM_TOTAL=$flash_fee" + else + echo "WARN unable to read FLASHLOAN_PREMIUM_TOTAL() from pool" + failures=1 + fi +fi + +exit "$failures" diff --git a/scripts/verify/check-chain138-native-protocol-stack-source.sh b/scripts/verify/check-chain138-native-protocol-stack-source.sh new file mode 100755 index 00000000..bd74cef5 --- /dev/null +++ b/scripts/verify/check-chain138-native-protocol-stack-source.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +failures=0 + +find_protocol_file() { + local mode="$1" + local needle="$2" + case "$mode" in + filename) + find "$PROJECT_ROOT/MEV_Bot" "$PROJECT_ROOT/smom-dbis-138" "$PROJECT_ROOT/vendor/chain138-protocols" \ + -path '*/node_modules/*' -prune -o \ + -path '*/target/*' -prune -o \ + -path '*/out/*' -prune -o \ + -path '*/broadcast/*' -prune -o \ + -type f -name "$needle" -print -quit + ;; + path) + find "$PROJECT_ROOT/MEV_Bot" "$PROJECT_ROOT/smom-dbis-138" "$PROJECT_ROOT/vendor/chain138-protocols" \ + -path '*/node_modules/*' -prune -o \ + -path '*/target/*' -prune -o \ + -path '*/out/*' -prune -o \ + -path '*/broadcast/*' -prune -o \ + -type f -path "*$needle*" -print -quit + ;; + *) + return 1 + ;; + esac +} + +report_family() { + local protocol="$1" family="$2" mode="$3" needle="$4" + local match + match="$(find_protocol_file "$mode" "$needle" || true)" + if [[ -n "$match" ]]; then + echo "FOUND $protocol :: $family :: ${match#$PROJECT_ROOT/}" + else + echo "MISS $protocol :: $family" + failures=1 + fi +} + +echo "=== Chain 138 native protocol stack source audit ===" + +echo "-- Aave native market families --" +report_family "Aave" "PoolAddressesProvider" "path" "/vendor/chain138-protocols/aave-v3-origin/src/contracts/protocol/configuration/PoolAddressesProvider.sol" +report_family "Aave" "Pool" "path" "/vendor/chain138-protocols/aave-v3-origin/src/contracts/protocol/pool/Pool.sol" +report_family "Aave" "PoolConfigurator" "path" "/vendor/chain138-protocols/aave-v3-origin/src/contracts/protocol/pool/PoolConfigurator.sol" +report_family "Aave" "AaveProtocolDataProvider" "path" "/vendor/chain138-protocols/aave-v3-origin/src/contracts/helpers/AaveProtocolDataProvider.sol" +report_family "Aave" "AaveOracle" "path" "/vendor/chain138-protocols/aave-v3-origin/src/contracts/misc/AaveOracle.sol" + +echo "-- GMX synthetics native market families --" +report_family "GMX" "Router" "path" "/vendor/chain138-protocols/gmx-synthetics/contracts/router/Router.sol" +report_family "GMX" "ExchangeRouter" "path" "/vendor/chain138-protocols/gmx-synthetics/contracts/router/ExchangeRouter.sol" +report_family "GMX" "Reader" "path" "/vendor/chain138-protocols/gmx-synthetics/contracts/reader/Reader.sol" +report_family "GMX" "OrderVault" "path" "/vendor/chain138-protocols/gmx-synthetics/contracts/order/OrderVault.sol" +report_family "GMX" "DepositVault" "path" "/vendor/chain138-protocols/gmx-synthetics/contracts/deposit/DepositVault.sol" +report_family "GMX" "WithdrawalVault" "path" "/vendor/chain138-protocols/gmx-synthetics/contracts/withdrawal/WithdrawalVault.sol" + +echo "-- dYdX native market families --" +report_family "dYdX" "SoloMargin" "filename" "SoloMargin.sol" +report_family "dYdX" "DataProvider" "filename" "DataProvider.sol" + +echo +if (( failures )); then + echo "RESULT missing native source families prevent truthful in-repo deployment of one or more remaining Chain 138 protocols." +else + echo "RESULT source families found for all audited native protocol stacks." +fi + +exit "$failures" diff --git a/scripts/verify/check-chain138-native-v2-venues.sh b/scripts/verify/check-chain138-native-v2-venues.sh new file mode 100755 index 00000000..905abbec --- /dev/null +++ b/scripts/verify/check-chain138-native-v2-venues.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +SMOM_ROOT="${PROJECT_ROOT}/smom-dbis-138" + +if [[ -f "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" ]]; then + # shellcheck source=/dev/null + source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh" +fi + +RPC_URL="${CHAIN138_RPC_URL:-${RPC_URL_138:-http://192.168.11.211:8545}}" +UNISWAP_JSON="${SMOM_ROOT}/deployments/chain138/uniswap-v2-native.json" +SUSHI_JSON="${SMOM_ROOT}/deployments/chain138/sushiswap-native.json" + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || { + echo "[fail] missing required command: $1" >&2 + exit 1 + } +} + +require_cmd cast +require_cmd jq + +check_code() { + local label="$1" + local address="$2" + local code + code="$(cast code --rpc-url "${RPC_URL}" "${address}" 2>/dev/null || true)" + [[ -n "${code}" && "${code}" != "0x" ]] || { + echo "[fail] ${label} missing bytecode at ${address}" >&2 + exit 1 + } + echo "[ok] ${label} bytecode present at ${address}" +} + +check_pair() { + local label="$1" + local pair="$2" + local reserves + reserves="$(cast call --rpc-url "${RPC_URL}" "${pair}" 'getReserves()(uint112,uint112,uint32)' 2>/dev/null || true)" + [[ -n "${reserves}" ]] || { + echo "[fail] ${label} getReserves failed at ${pair}" >&2 + exit 1 + } + local reserve0 reserve1 + reserve0="$(printf '%s\n' "${reserves}" | sed -n '1p' | awk '{print $1}')" + reserve1="$(printf '%s\n' "${reserves}" | sed -n '2p' | awk '{print $1}')" + [[ "${reserve0}" != "0" && "${reserve1}" != "0" ]] || { + echo "[fail] ${label} has zero reserves (${reserve0}/${reserve1})" >&2 + exit 1 + } + echo "[ok] ${label} reserves ${reserve0}/${reserve1}" +} + +check_stack() { + local label="$1" + local json="$2" + [[ -f "${json}" ]] || { + echo "[fail] missing deployment artifact ${json}" >&2 + exit 1 + } + + local factory router + factory="$(jq -r '.factory' "${json}")" + router="$(jq -r '.router' "${json}")" + check_code "${label} factory" "${factory}" + check_code "${label} router" "${router}" + + jq -r '.pairs | to_entries[] | [.key, .value] | @tsv' "${json}" | while IFS=$'\t' read -r key pair; do + check_code "${label} ${key} pair" "${pair}" + check_pair "${label} ${key} pair" "${pair}" + done +} + +check_stack "Uniswap v2" "${UNISWAP_JSON}" +check_stack "SushiSwap" "${SUSHI_JSON}" + +echo "[ok] Chain 138 native V2 venues verified" diff --git a/scripts/verify/check-chain138-remaining-protocol-env.sh b/scripts/verify/check-chain138-remaining-protocol-env.sh new file mode 100755 index 00000000..88f68438 --- /dev/null +++ b/scripts/verify/check-chain138-remaining-protocol-env.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +SMOM_ROOT="$PROJECT_ROOT/smom-dbis-138" +SURFACE_JSON="$PROJECT_ROOT/config/chain138-remaining-protocol-surface.json" + +if [[ -f "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" ]]; then + # shellcheck disable=SC1091 + source "$SMOM_ROOT/scripts/lib/deployment/dotenv.sh" + load_deployment_env --repo-root "$SMOM_ROOT" +fi + +command -v jq >/dev/null 2>&1 || { echo "jq is required" >&2; exit 1; } +command -v cast >/dev/null 2>&1 || { echo "cast is required" >&2; exit 1; } + +RPC_URL="${RPC_URL_138:-${CHAIN138_RPC_URL:-${RPC_URL:-http://192.168.11.211:8545}}}" + +echo "=== Chain 138 remaining protocol env inventory ===" +echo "rpcUrl=$RPC_URL" + +check_var() { + local label="$1" var="$2" + local value="${!var:-}" + if [[ -n "$value" ]]; then + echo "SET $label -> $var=$value" + return 0 + fi + echo "MISS $label -> $var" + return 1 +} + +looks_like_contract_var() { + local var="$1" + case "$var" in + *_START_BLOCK|*_OWNER|*_TREASURY) + return 1 + ;; + *) + return 0 + ;; + esac +} + +check_code() { + local protocol="$1" var="$2" + local value="${!var:-}" + [[ "$value" =~ ^0x[0-9a-fA-F]{40}$ ]] || return 0 + looks_like_contract_var "$var" || return 0 + local code + code="$(cast code "$value" --rpc-url "$RPC_URL" 2>/dev/null || true)" + if [[ -n "$code" && "$code" != "0x" ]]; then + echo "CODE $protocol -> $var bytecode present" + return 0 + fi + echo "NOCODE $protocol -> $var has no bytecode at $value" + return 1 +} + +failures=0 + +while IFS=$'\t' read -r key status env_var; do + if check_var "$key ($status)" "$env_var"; then + if ! check_code "$key" "$env_var"; then + failures=1 + fi + else + failures=1 + fi +done < <(jq -r '.protocols[] | .key as $k | .status as $s | .requiredEnv[] | [$k, $s, .] | @tsv' "$SURFACE_JSON") + +exit "$failures" diff --git a/scripts/verify/mainnet-aave-top-assets-dex-parity.py b/scripts/verify/mainnet-aave-top-assets-dex-parity.py new file mode 100755 index 00000000..62a6a425 --- /dev/null +++ b/scripts/verify/mainnet-aave-top-assets-dex-parity.py @@ -0,0 +1,398 @@ +#!/usr/bin/env python3 +""" +On-chain Uniswap V3 **Quoter v1** implied USD for Aave V3 (Ethereum) top underlyings. + +Reads `config/mainnet-aave-dex-parity.json`, calls `quoteExactInputSingle` / `quoteExactInput` +on `quoterV1` (default `0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6`), compares optional +DeFi Llama `coins` USD, writes JSON (stdout) and optional CSV. + +Requires: `cast` (Foundry) on PATH, `ETHEREUM_MAINNET_RPC` (or `--rpc-url`). + +Usage: + source scripts/lib/load-project-env.sh + python3 scripts/verify/mainnet-aave-top-assets-dex-parity.py + python3 scripts/verify/mainnet-aave-top-assets-dex-parity.py --csv reports/status/mainnet_aave_dex_parity.csv + python3 scripts/verify/mainnet-aave-top-assets-dex-parity.py --no-llama --config /path/to/custom.json +""" + +from __future__ import annotations + +import argparse +import csv +import json +import os +import re +import shutil +import subprocess +import sys +import urllib.error +import urllib.request +import urllib.parse +from decimal import Decimal +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple + + +def _repo_root() -> Path: + return Path(__file__).resolve().parents[2] + + +def _load_json(path: Path) -> dict: + with path.open() as f: + return json.load(f) + + +def _build_path_hex(tokens: List[str], fees: List[int]) -> str: + if len(tokens) < 2 or len(fees) != len(tokens) - 1: + raise ValueError("path: need tokens N and fees N-1") + + def addr(s: str) -> bytes: + s = s.strip().lower() + if not s.startswith("0x") or len(s) != 42: + raise ValueError(f"bad address: {s}") + return bytes.fromhex(s[2:]) + + def fee_u24(x: int) -> bytes: + if x < 0 or x >= 1 << 24: + raise ValueError(f"bad fee: {x}") + return x.to_bytes(3, "big") + + out = b"" + for i in range(len(fees)): + out += addr(tokens[i]) + out += fee_u24(fees[i]) + out += addr(tokens[-1]) + return "0x" + out.hex() + + +def _cast_quiet() -> str: + c = shutil.which("cast") + if not c: + print("[fail] Foundry `cast` not found on PATH", file=sys.stderr) + sys.exit(1) + return c + + +def _cast_call( + cast: str, + rpc: str, + to: str, + sig: str, + args: List[str], +) -> str: + cmd = [cast, "call", to, sig, *args, "--rpc-url", rpc] + p = subprocess.run( + cmd, + capture_output=True, + text=True, + timeout=120, + ) + if p.returncode != 0: + err = (p.stderr or p.stdout or "").strip() + raise RuntimeError(err or f"cast exit {p.returncode}") + return p.stdout.strip() + + +def _parse_uint_out(stdout: str) -> int: + # "12345 [1.234e10]" or hex + s = stdout.splitlines()[0].strip() + m = re.match(r"^(\d+)", s) + if m: + return int(m.group(1)) + if s.startswith("0x"): + return int(s, 16) + raise ValueError(f"unparsed cast output: {stdout[:200]}") + + +def _quoter_single( + cast: str, + rpc: str, + quoter: str, + token_in: str, + token_out: str, + fee: int, + amount_in: int, +) -> int: + out = _cast_call( + cast, + rpc, + quoter, + "quoteExactInputSingle(address,address,uint24,uint256,uint160)(uint256)", + [token_in, token_out, str(fee), str(amount_in), "0"], + ) + return _parse_uint_out(out) + + +def _quoter_path( + cast: str, + rpc: str, + quoter: str, + path_hex: str, + amount_in: int, +) -> int: + out = _cast_call( + cast, + rpc, + quoter, + "quoteExactInput(bytes,uint256)(uint256)", + [path_hex, str(amount_in)], + ) + return _parse_uint_out(out) + + +def _llama_prices(addresses: List[str]) -> Dict[str, float]: + if not addresses: + return {} + batch = ",".join(f"ethereum:{a.lower()}" for a in addresses) + url = f"https://coins.llama.fi/prices/current/{batch}" + req = urllib.request.Request(url, headers={"User-Agent": "proxmox-verify/1.0"}) + try: + with urllib.request.urlopen(req, timeout=45) as r: + data = json.load(r) + except (urllib.error.URLError, TimeoutError) as e: + print(f"[warn] DeFiLlama coins fetch failed: {e}", file=sys.stderr) + return {} + out: Dict[str, float] = {} + for k, v in (data.get("coins") or {}).items(): + addr = k.split(":", 1)[-1].lower() + try: + out[addr] = float(v.get("price") or 0) + except (TypeError, ValueError): + continue + return out + + +def _implied_usd( + amount_out_usdc: int, + amount_in: int, + decimals_in: int, + usdc_decimals: int, +) -> Decimal: + if amount_in <= 0: + return Decimal(0) + ai = Decimal(amount_in) / Decimal(10**decimals_in) + usd_out = Decimal(amount_out_usdc) / Decimal(10**usdc_decimals) + return usd_out / ai + + +def _compose_via_weth( + cast: str, + rpc: str, + quoter: str, + token_in: str, + amount_in: int, + decimals_in: int, + weth: str, + usdc: str, + usdc_dec: int, + fee_to_weth_list: List[int], + usdc_fee: int, +) -> Tuple[int, str]: + """ + implied USD/token = (WETH out per amount_in) / (amount in human) * (USDC per 1 WETH), + using Quoter for token->WETH and WETH->USDC. + Returns (usdc_numerator_scaled, description) where we store synthetic USDC-out for 1 unit + by reporting impliedUsd directly in caller — here return weth_out and build desc. + """ + best_w = -1 + best_fw: Optional[int] = None + for fee in fee_to_weth_list: + try: + w = _quoter_single(cast, rpc, quoter, token_in, weth, fee, amount_in) + if w > best_w: + best_w = w + best_fw = fee + except Exception: + continue + if best_fw is None or best_w < 0: + raise RuntimeError("compose_via_weth: no token->WETH fee tier succeeded") + usdc_1eth = _quoter_single(cast, rpc, quoter, weth, usdc, usdc_fee, 10**18) + # USD per 1 full token (human) = (weth_out/1e18) / (amount_in/10^dec) * (usdc_1eth/1e6) + weth_per_token = Decimal(best_w) / Decimal(10**18) / (Decimal(amount_in) / Decimal(10**decimals_in)) + usd_per_weth = Decimal(usdc_1eth) / Decimal(10**usdc_dec) + imp = weth_per_token * usd_per_weth + desc = f"compose token->WETH fee={best_fw} × WETH->USDC fee={usdc_fee} (WETH_out={best_w})" + # Return synthetic "usdc out if we sold amount_in at imp" for display: imp * human_units * 10^6 + synthetic_usdc = int(imp * (Decimal(amount_in) / Decimal(10**decimals_in)) * Decimal(10**usdc_dec)) + return synthetic_usdc, desc + + +def main() -> None: + ap = argparse.ArgumentParser(description="Mainnet Aave top assets — Uniswap V3 quoter implied USD") + ap.add_argument( + "--config", + type=Path, + default=_repo_root() / "config" / "mainnet-aave-dex-parity.json", + help="Path to parity JSON config", + ) + ap.add_argument("--rpc-url", default=os.environ.get("ETHEREUM_MAINNET_RPC", "").strip(), help="Ethereum JSON-RPC") + ap.add_argument("--csv", type=Path, default=None, help="Write CSV rows") + ap.add_argument("--no-llama", action="store_true", help="Skip DeFiLlama reference prices") + ap.add_argument( + "--strict", + action="store_true", + help="Exit 1 if any asset row has error (for CI)", + ) + ap.add_argument( + "--only", + default="", + help="Comma-separated asset symbols to run (default: all). Example: --only WETH,WBTC,rsETH", + ) + args = ap.parse_args() + + rpc = args.rpc_url or os.environ.get("ETH_MAINNET_RPC_URL", "").strip() + if not rpc: + print("[fail] Set ETHEREUM_MAINNET_RPC or pass --rpc-url", file=sys.stderr) + sys.exit(1) + + cfg = _load_json(args.config) + quoter = cfg.get("quoterV1") or "0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6" + ref = cfg.get("referenceStable") or {} + usdc_dec = int(ref.get("decimals") or 6) + fee_tiers: List[int] = [int(x) for x in cfg.get("feeTiersTry") or [100, 500, 3000, 10000]] + weth_addr = (cfg.get("weth") or "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2").strip() + assets: List[dict] = cfg.get("assets") or [] + only_set = {s.strip().upper() for s in args.only.split(",") if s.strip()} if args.only.strip() else None + + cast = _cast_quiet() + + want_llama = not args.no_llama + llama: Dict[str, float] = {} + if want_llama: + addrs = [a["address"] for a in assets if a.get("address")] + llama = _llama_prices(addrs) + + rows_out: List[Dict[str, Any]] = [] + + for asset in assets: + sym = asset.get("symbol") or "?" + if only_set is not None and sym.strip().upper() not in only_set: + continue + addr = (asset.get("address") or "").strip() + dec_in = int(asset.get("decimals") or 18) + amount_in = int(asset.get("amountIn") or 0) + q = asset.get("quote") or {} + qtype = (q.get("type") or "").strip() + label = q.get("label") or qtype + + row: Dict[str, Any] = { + "symbol": sym, + "token": addr, + "decimals": dec_in, + "amountIn": str(amount_in), + "quoteLabel": label, + "quoter": quoter, + } + + try: + if qtype == "identity_usd": + row["amountOutUsdc"] = str(amount_in) + row["feeTierOrPath"] = "identity" + imp = _implied_usd(amount_in, amount_in, dec_in, usdc_dec) + elif qtype == "compose_via_weth": + usdc_addr = (ref.get("address") or "").strip() + ftw = [int(x) for x in (q.get("feeTiersToWeth") or fee_tiers)] + usf = int(q.get("usdcFee") or 500) + syn, desc = _compose_via_weth( + cast, + rpc, + quoter, + addr, + amount_in, + dec_in, + weth_addr, + usdc_addr, + usdc_dec, + ftw, + usf, + ) + row["amountOutUsdc"] = str(syn) + row["feeTierOrPath"] = desc[:500] + imp = Decimal(syn) / (Decimal(amount_in) / Decimal(10**dec_in)) / Decimal(10**usdc_dec) + elif qtype == "single_best": + token_out = (q.get("tokenOut") or ref.get("address") or "").strip() + if not token_out: + raise ValueError("single_best needs tokenOut") + tiers = [int(x) for x in q.get("feeTiersTry")] if q.get("feeTiersTry") else fee_tiers + best_amt = -1 + best_fee: Optional[int] = None + for fee in tiers: + try: + amt = _quoter_single(cast, rpc, quoter, addr, token_out, fee, amount_in) + if amt > best_amt: + best_amt = amt + best_fee = fee + except Exception: + continue + if best_fee is None or best_amt < 0: + raise RuntimeError("no successful fee tier (all reverted or empty)") + row["amountOutUsdc"] = str(best_amt) + row["feeTierOrPath"] = f"single fee={best_fee}" + imp = _implied_usd(best_amt, amount_in, dec_in, usdc_dec) + elif qtype == "path": + tokens = q.get("tokens") or [] + fees = [int(x) for x in (q.get("fees") or [])] + path_hex = _build_path_hex(list(tokens), fees) + amt = _quoter_path(cast, rpc, quoter, path_hex, amount_in) + row["amountOutUsdc"] = str(amt) + row["feeTierOrPath"] = path_hex[:66] + "..." + imp = _implied_usd(amt, amount_in, dec_in, usdc_dec) + else: + raise ValueError(f"unknown quote.type: {qtype}") + + row["impliedUsd"] = str(imp) + la = llama.get(addr.lower()) + row["llamaUsd"] = la + if la and la > 0 and imp and imp > 0: + row["diffVsLlamaBps"] = float((imp / Decimal(str(la)) - Decimal(1)) * Decimal(10000)) + else: + row["diffVsLlamaBps"] = None + row["error"] = None + except Exception as e: + row["error"] = str(e) + row["impliedUsd"] = None + row["amountOutUsdc"] = None + row["feeTierOrPath"] = None + row["llamaUsd"] = llama.get(addr.lower()) + row["diffVsLlamaBps"] = None + + rows_out.append(row) + + rpc_host = urllib.parse.urlparse(rpc).netloc or rpc[:48] + out = { + "config": str(args.config), + "rpcUrlHost": rpc_host[:120], + "quoterV1": quoter, + "referenceStable": ref, + "rows": rows_out, + } + print(json.dumps(out, indent=2)) + + if args.csv: + args.csv.parent.mkdir(parents=True, exist_ok=True) + fields = [ + "symbol", + "token", + "impliedUsd", + "llamaUsd", + "diffVsLlamaBps", + "quoteLabel", + "feeTierOrPath", + "amountOutUsdc", + "error", + ] + with args.csv.open("w", newline="") as f: + w = csv.DictWriter(f, fieldnames=fields, extrasaction="ignore") + w.writeheader() + for r in rows_out: + w.writerow({k: r.get(k) for k in fields}) + print(f"[ok] wrote {args.csv}", file=sys.stderr) + + errs = sum(1 for r in rows_out if r.get("error")) + if args.strict and errs: + print(f"[fail] {errs} asset(s) failed (see error fields)", file=sys.stderr) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/token-aggregation-build/config/chain138-aave-rollout-manifest.example.json b/token-aggregation-build/config/chain138-aave-rollout-manifest.example.json new file mode 100644 index 00000000..4990a2e4 --- /dev/null +++ b/token-aggregation-build/config/chain138-aave-rollout-manifest.example.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Canonical manifest template for the native Chain 138 Aave rollout.", + "chainId": 138, + "network": "Chain 138", + "aave": { + "pool": "", + "poolAddressesProvider": "", + "poolDataProvider": "", + "startBlock": "", + "executorTreasury": "", + "executorOwner": "", + "quotePushReceiverOwner": "" + } +} diff --git a/token-aggregation-build/config/chain138-aave-v3-origin-manifest.example.json b/token-aggregation-build/config/chain138-aave-v3-origin-manifest.example.json new file mode 100644 index 00000000..c16faf2f --- /dev/null +++ b/token-aggregation-build/config/chain138-aave-v3-origin-manifest.example.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Chain 138 native Aave V3 Origin market deployment manifest template.", + "chainId": 138, + "network": "Chain 138", + "contractName": "Chain138AaveV3OriginMarket", + "roles": { + "marketOwner": "", + "poolAdmin": "", + "emergencyAdmin": "" + }, + "flags": { + "l2": false + }, + "marketConfig": { + "marketId": "Chain 138 Aave V3 Market", + "providerId": 138, + "oracleDecimals": 8, + "networkBaseTokenPriceInUsdProxyAggregator": "", + "marketReferenceCurrencyPriceInUsdProxyAggregator": "", + "l2SequencerUptimeFeed": "", + "l2PriceOracleSentinelGracePeriod": 0, + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", + "wrappedNativeToken": "", + "flashLoanPremium": "5000000000000000", + "incentivesProxy": "", + "treasury": "" + } +} diff --git a/token-aggregation-build/config/chain138-gmx-synthetics-manifest.example.json b/token-aggregation-build/config/chain138-gmx-synthetics-manifest.example.json new file mode 100644 index 00000000..1a4be48e --- /dev/null +++ b/token-aggregation-build/config/chain138-gmx-synthetics-manifest.example.json @@ -0,0 +1,86 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Chain 138 native GMX synthetics deployment manifest template.", + "chainId": 138, + "network": "chain138", + "rpcUrl": "http://192.168.11.211:8545", + "explorer": { + "apiUrl": "https://explorer.d-bis.org/api", + "browserUrl": "https://explorer.d-bis.org" + }, + "general": { + "feeReceiver": "", + "holdingAddress": "", + "sequencerUptimeFeed": "0x0000000000000000000000000000000000000000", + "sequencerGraceDuration": 300, + "maxUiFeeFactor": "0", + "maxAutoCancelOrders": 6, + "maxTotalCallbackGasLimitForAutoCancelOrders": 5000000, + "minHandleExecutionErrorGas": 1200000, + "minHandleExecutionErrorGasToForward": 1000000, + "minAdditionalGasForExecution": 1000000, + "refundExecutionFeeGasLimit": 200000, + "depositGasLimit": 2050000, + "withdrawalGasLimit": 1500000, + "shiftGasLimit": 2500000, + "createDepositGasLimit": 5000000, + "createGlvDepositGasLimit": 5000000, + "createWithdrawalGasLimit": 5000000, + "createGlvWithdrawalGasLimit": 5000000, + "singleSwapGasLimit": 1000000, + "increaseOrderGasLimit": 3900000, + "decreaseOrderGasLimit": 3900000, + "swapOrderGasLimit": 3400000, + "glvPerMarketGasLimit": 100000, + "glvDepositGasLimit": 2000000, + "glvWithdrawalGasLimit": 2000000, + "glvShiftGasLimit": 3000000, + "tokenTransferGasLimit": 200000, + "nativeTokenTransferGasLimit": 50000, + "setTraderReferralCodeGasLimit": 200000, + "registerCodeGasLimit": 200000, + "estimatedGasFeeBaseAmount": 600000, + "estimatedGasPerOraclePrice": 250000, + "estimatedGasFeeMultiplierFactor": "1000000000000000000000000000000", + "executionGasFeeBaseAmount": 600000, + "executionGasPerOraclePrice": 250000, + "executionGasFeeMultiplierFactor": "1000000000000000000000000000000", + "requestExpirationTime": 300, + "maxSwapPathLength": 3, + "maxCallbackGasLimit": 2000000, + "minCollateralUsd": "1000000000000000000000000000000", + "minPositionSizeUsd": "1000000000000000000000000000000", + "claimableCollateralTimeDivisor": 3600, + "claimableCollateralDelay": 432000, + "positionFeeReceiverFactor": "0", + "swapFeeReceiverFactor": "0", + "borrowingFeeReceiverFactor": "0", + "liquidationFeeReceiverFactor": "0", + "skipBorrowingFeeForSmallerSide": true, + "maxExecutionFeeMultiplierFactor": "100000000000000000000000000000000", + "oracleProviderMinChangeDelay": 3600, + "configMaxPriceAge": 180, + "gelatoRelayFeeMultiplierFactor": "0", + "gelatoRelayFeeBaseAmount": 0, + "relayFeeAddress": "0x0000000000000000000000000000000000000000", + "maxRelayFeeUsdForSubaccount": "0", + "maxDataLength": 18, + "multichainProviders": {}, + "multichainEndpoints": {}, + "srcChainIds": {}, + "eids": {} + }, + "roles": { + "CONTROLLER": {}, + "ORDER_KEEPER": {}, + "ADL_KEEPER": {}, + "LIQUIDATION_KEEPER": {}, + "MARKET_KEEPER": {}, + "FROZEN_ORDER_KEEPER": {}, + "CONFIG_KEEPER": {}, + "LIMITED_CONFIG_KEEPER": {}, + "TIMELOCK_ADMIN": {} + }, + "tokens": {}, + "markets": [] +} diff --git a/token-aggregation-build/config/chain138-remaining-protocol-surface.json b/token-aggregation-build/config/chain138-remaining-protocol-surface.json new file mode 100644 index 00000000..61506e62 --- /dev/null +++ b/token-aggregation-build/config/chain138-remaining-protocol-surface.json @@ -0,0 +1,76 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Canonical Chain 138 remaining native protocol surface inventory for Aave, GMX, and dYdX.", + "version": "1.0.0", + "updated": "2026-04-15", + "chainId": 138, + "network": "Chain 138", + "protocols": [ + { + "key": "aave", + "status": "source-backed", + "discoveredAddresses": {}, + "sourceSubmodule": "vendor/chain138-protocols/aave-v3-origin", + "discoveryEvidence": [ + "2026-04-15: explorer search /api/v2/search?q=Aave returned items=[]", + "2026-04-15: token-aggregation provider capabilities for chainId=138 did not advertise provider=aave", + "2026-04-15: MEV venue coverage and native-venue-coverage for chainId=138 did not include venue=aave", + "2026-04-15: eth_getLogs scan for Aave PoolAddressesProvider event topics returned no matches from block 0..latest" + ], + "requiredEnv": [ + "CHAIN_138_AAVE_POOL", + "CHAIN_138_AAVE_POOL_ADDRESSES_PROVIDER", + "CHAIN_138_AAVE_POOL_DATA_PROVIDER", + "CHAIN_138_AAVE_START_BLOCK", + "CHAIN_138_AAVE_EXECUTOR_TREASURY", + "CHAIN_138_AAVE_EXECUTOR_OWNER", + "CHAIN_138_AAVE_QUOTE_PUSH_RECEIVER_OWNER" + ], + "deployerScripts": [ + "scripts/deployment/deploy-chain138-aave-v3-execution-stack.sh", + "scripts/deployment/deploy-chain138-aave-quote-push-receiver.sh", + "scripts/deployment/publish-chain138-aave-runtime-from-artifacts.sh" + ], + "verifierScripts": [ + "scripts/verify/check-chain138-remaining-protocol-env.sh", + "scripts/verify/check-chain138-aave-rollout-readiness.sh" + ] + }, + { + "key": "gmx", + "status": "source-backed", + "discoveredAddresses": {}, + "sourceSubmodule": "vendor/chain138-protocols/gmx-synthetics", + "discoveryEvidence": [ + "2026-04-15: explorer search /api/v2/search?q=GMX returned items=[]", + "2026-04-15: token-aggregation provider capabilities for chainId=138 did not advertise provider=gmx", + "2026-04-15: MEV venue coverage and native-venue-coverage for chainId=138 did not include venue=gmx", + "2026-04-15: imported official upstream source submodule gmx-io/gmx-synthetics into vendor/chain138-protocols/gmx-synthetics" + ], + "requiredEnv": [ + "CHAIN_138_GMX_ROUTER", + "CHAIN_138_GMX_EXCHANGE_ROUTER", + "CHAIN_138_GMX_READER", + "CHAIN_138_GMX_ORDER_VAULT", + "CHAIN_138_GMX_DEPOSIT_VAULT", + "CHAIN_138_GMX_WITHDRAWAL_VAULT", + "CHAIN_138_GMX_START_BLOCK" + ] + }, + { + "key": "dydx", + "status": "inventory-only", + "discoveredAddresses": {}, + "discoveryEvidence": [ + "2026-04-15: explorer search /api/v2/search?q=dydx, dYdX, and SoloMargin returned items=[]", + "2026-04-15: token-aggregation provider capabilities for chainId=138 did not advertise provider=dydx", + "2026-04-15: MEV venue coverage and native-venue-coverage for chainId=138 did not include venue=dydx" + ], + "requiredEnv": [ + "CHAIN_138_DYDX_SOLO", + "CHAIN_138_DYDX_DATA_PROVIDER", + "CHAIN_138_DYDX_START_BLOCK" + ] + } + ] +}