Add Chain 138 Aave and GMX rollout scaffolding

This commit is contained in:
defiQUG
2026-04-16 11:36:55 -07:00
parent 4f7cda9b2f
commit dc4f4dfcc5
32 changed files with 2563 additions and 0 deletions

View File

@@ -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": ""
}
}

View File

@@ -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": ""
}
}

View File

@@ -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": []
}

View File

@@ -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"
]
}
]
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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 MetaMasks 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** | CMCs 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)
MetaMasks **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)

View File

@@ -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`

View File

@@ -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 MetaMasks 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).

View File

@@ -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.

View File

@@ -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.

View File

@@ -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:-...}"

View File

@@ -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[@]}"

View File

@@ -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
)

View File

@@ -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"
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"

View File

@@ -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 <manifest.json> <output.sol>", 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())

View File

@@ -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 <manifest.json> <output-dir>", 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())

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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"

View File

@@ -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()

View File

@@ -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": ""
}
}

View File

@@ -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": ""
}
}

View File

@@ -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": []
}

View File

@@ -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"
]
}
]
}