From 2b52cc6e325889adb128543bfb68abfdf7a084bc Mon Sep 17 00:00:00 2001 From: defiQUG Date: Sun, 12 Apr 2026 18:21:05 -0700 Subject: [PATCH] refactor(archive): move historical contracts and adapters to archive directory - Archived multiple non-EVM adapters (Algorand, Hedera, Tron, TON, Cosmos, Solana) and compliance contracts (IndyVerifier) to `archive/solidity/contracts/`. - Updated documentation to reflect the historical status of archived components. - Adjusted `foundry.toml` and `README.md` for clarity on historical dependencies and configurations. - Enhanced Makefile and package.json scripts for improved contract testing and building processes. - Removed obsolete contracts (AlltraCustomBridge, CommodityCCIPBridge, ISO4217WCCIPBridge, VaultBridgeAdapter) from the main directory. - Updated implementation reports to indicate archived status for various components. --- COMPLETE_MULTI_CHAIN_DEPLOYMENT.md | 14 +- IMPLEMENTATION_REPORT.md | 64 ++-- Makefile | 15 +- README.md | 2 +- UNIVERSAL_BRIDGE_IMPLEMENTATION_COMPLETE.md | 32 +- archive/solidity/README.md | 27 ++ .../contracts}/bridge/AlltraCustomBridge.sol | 0 .../contracts}/bridge/CommodityCCIPBridge.sol | 0 .../contracts}/bridge/ISO4217WCCIPBridge.sol | 0 .../contracts}/bridge/VaultBridgeAdapter.sol | 0 .../adapters/non-evm/AlgorandAdapter.sol | 0 .../bridge/adapters/non-evm/CosmosAdapter.sol | 0 .../bridge/adapters/non-evm/HederaAdapter.sol | 0 .../bridge/adapters/non-evm/SolanaAdapter.sol | 0 .../bridge/adapters/non-evm/TONAdapter.sol | 0 .../bridge/adapters/non-evm/TronAdapter.sol | 0 .../UniversalCcipAtomicSettlementAdapter.sol | 0 .../interfaces/IAtomicUnwindAdapter.sol | 0 .../bridge/modules/BridgeModuleRegistry.sol | 0 .../ccip-integration/CCIPTxReporter.sol | 0 .../contracts}/ccip/CCIPRouterOptimized.sol | 0 .../contracts}/compliance/IndyVerifier.sol | 0 .../config/ConfigurationRegistry.sol | 0 .../contracts}/dbis/DBIS_EIP712Lib.sol | 0 .../contracts}/interfaces/IAggregator.sol | 0 .../contracts}/liquidity/PoolManager.sol | 0 .../contracts}/nft/GRUFormulasNFT.sol | 0 .../contracts}/plugins/PluginRegistry.sol | 0 .../registry/TruthNetworkAdapter.sol | 0 .../registry/handlers/CommodityHandler.sol | 0 .../registry/handlers/ERC20Handler.sol | 0 .../registry/handlers/GRUHandler.sol | 0 .../registry/handlers/ISO4217WHandler.sol | 0 .../registry/handlers/SecurityHandler.sol | 0 .../registry/interfaces/IAssetTypeHandler.sol | 0 .../contracts}/upgrades/ProxyFactory.sol | 0 .../contracts}/vault/BridgeVaultExtension.sol | 0 .../vault/adapters/PMMPriceProvider.sol | 0 .../contracts}/vault/errors/VaultErrors.sol | 0 .../vault/interfaces/IVaultStrategy.sol | 0 .../vault/libraries/CurrencyValidation.sol | 0 .../vault/libraries/MonetaryFormulas.sol | 0 .../vault/libraries/XAUTriangulation.sol | 0 contracts/dbis/BUILD_NOTES.md | 2 +- .../flash/AaveQuotePushFlashReceiver.sol | 34 +- contracts/flash/QuotePushTreasuryManager.sol | 165 +++++++++ docs/E2E_TESTING_AND_DEPLOYMENT_STATUS.md | 2 +- ...ASTER_CONTRACTS_AND_INFRASTRUCTURE_LIST.md | 52 +-- docs/PARALLEL_COMPLETION_TASK_LIST.md | 2 +- docs/architecture/DIRECTORY_STRUCTURE.md | 2 +- docs/architecture/FOUNDRY_MONOREPO_SCOPES.md | 113 ++++++ docs/bridge/UPGRADE_AND_PAUSE_RUNBOOKS.md | 2 +- docs/ccip-integration/DEPLOYMENT_GUIDE.md | 7 +- docs/ccip-integration/QUICK_START.md | 4 +- docs/ccip-integration/README.md | 13 +- .../CHAIN138_DEPLOYMENT_COMPLETE.md | 8 +- .../CHAIN138_DEPLOYMENT_STATUS_COMPLETE.md | 8 +- docs/deployment/COMPILATION_STATUS.md | 3 +- .../deployment/MAINNET_DEPLOYMENT_COMPLETE.md | 4 +- docs/deployment/MAINNET_DEPLOYMENT_STATUS.md | 4 +- docs/guides/ADDING_NEW_ASSET_TYPE.md | 6 +- docs/guides/CONTRACT_INVENTORY.md | 13 +- .../OPENZEPPELIN_DEPENDENCY_ASSESSMENT.md | 4 +- docs/guides/OPENZEPPELIN_TASKS_CHECKLIST.md | 4 +- docs/integration/DODO_PMM_INTEGRATION.md | 2 +- docs/nft/GRU_FORMULAS_NFT.md | 4 +- .../status-reports/ALL_TASKS_COMPLETE.md | 2 +- .../status-reports/FINAL_COMPLETION_STATUS.md | 2 +- docs/operations/tasks/TODO.md | 8 +- docs/tokenization/IMPLEMENTATION_COMPLETE.md | 6 +- docs/vault/COMPLIANCE_REQUIREMENTS.md | 2 +- docs/vault/COMPLIANCE_VERIFICATION.md | 14 +- docs/vault/IMPLEMENTATION_SUMMARY.md | 10 +- ...aveQuotePushFlashReceiverMainnetFork.t.sol | 2 +- foundry.toml | 4 + package.json | 21 +- .../DeployAaveQuotePushFlashReceiver.s.sol | 5 +- .../DeployQuotePushTreasuryManager.s.sol | 72 ++++ .../ManageQuotePushTreasuryManager.s.sol | 50 +++ ...dMainnetAaveCwusdcUsdcQuotePushCycle.s.sol | 173 ++++++++++ ...eepAaveQuotePushFlashReceiverSurplus.s.sol | 47 +++ .../tokenization/DeployTokenRegistry.s.sol | 0 .../tokenization/DeployTokenizedEUR.s.sol | 0 .../tokenization/RegisterToken.s.sol | 0 scripts/automation/prepare-deployment.sh | 1 + scripts/automation/run-all-automated-tasks.sh | 5 +- scripts/automation/run-tests-parallel.sh | 3 +- .../deploy-all-ccip-mainnet.sh | 3 +- .../ccip-deployment/deploy-ccip-reporter.js | 71 +--- scripts/compile-and-test-tokenfactory.sh | 2 +- scripts/complete-configuration.sh | 12 +- scripts/deploy-all-compliance.sh | 12 +- scripts/deploy-all-utilities.sh | 12 +- scripts/deploy-and-integrate-all.sh | 12 +- scripts/deploy-ccip-receiver-direct.sh | 2 +- scripts/deploy-iso4217w-system.sh | 6 +- scripts/deploy-relay-mainnet.sh | 5 +- scripts/deploy-vault-system.sh | 6 +- .../compile-test-mainnet-contracts.sh | 6 +- scripts/deployment/complete-all-tasks.sh | 6 +- ...loy-all-mainnets-with-mapper-oracle-pmm.sh | 17 +- scripts/deployment/deploy-all-ordered.sh | 5 +- scripts/deployment/deploy-all-phases.sh | 16 +- scripts/deployment/deploy-all.sh | 10 +- scripts/deployment/deploy-bridge-contracts.sh | 15 +- .../deployment/deploy-chain138-complete.sh | 18 +- .../deployment/deploy-contracts-once-ready.sh | 17 +- .../deployment/deploy-contracts-ordered.sh | 5 +- .../deployment/deploy-contracts-parallel.sh | 17 +- .../deployment/deploy-contracts-unified.sh | 3 +- .../deployment/deploy-optional-future-all.sh | 20 +- scripts/deployment/deploy-tokenization.sh | 20 +- .../dry-run-enhanced-swap-router-chain138.sh | 5 +- ...ry-run-enhanced-swap-router-v2-chain138.sh | 1 + .../final-mainnet-deployment-report.sh | 14 +- .../generate-prioritized-deployment-plan.sh | 10 +- .../inventory-register-dodo-pools-chain138.sh | 11 +- .../list-remaining-mainnet-contracts.sh | 10 +- scripts/deployment/phase2-deploy-core.sh | 11 +- scripts/deployment/phase3-deploy-router.sh | 11 +- .../deployment/phase4-deploy-integration.sh | 11 +- scripts/deployment/phase5-initialize.sh | 11 +- .../prioritize-mainnet-deployments.sh | 10 +- scripts/deployment/setup-chain138-env.sh | 3 +- scripts/forge/report-contract-reachability.py | 140 ++++++++ scripts/forge/scope.sh | 324 ++++++++++++++++++ scripts/lib/deployment/dotenv.sh | 3 +- scripts/lib/forge-scope.sh | 45 +++ scripts/lib/init.sh | 2 +- scripts/mint-for-liquidity.sh | 3 +- scripts/quick-compile-test.sh | 2 +- scripts/reserve/keeper-service.sh | 6 +- scripts/reserve/setup-complete.sh | 6 +- scripts/run-lint-test-build-deploy.sh | 9 +- scripts/security/run-slither.sh | 2 +- scripts/test-tokenfactory-compile.sh | 2 +- scripts/utils/get-mapped-address.sh | 5 +- services/relay/README.md | 6 +- services/relay/src/MessageQueue.js | 113 +++++- services/relay/src/RelayService.js | 10 +- services/relay/src/config.js | 6 + services/relay/test.js | 78 ++++- test-results/foundry.json | 2 +- test/flash/AaveQuotePushFlashReceiver.t.sol | 50 +++ ...aveQuotePushFlashReceiverMainnetFork.t.sol | 45 ++- test/flash/QuotePushTreasuryManager.t.sol | 109 ++++++ 146 files changed, 2010 insertions(+), 423 deletions(-) create mode 100644 archive/solidity/README.md rename {contracts => archive/solidity/contracts}/bridge/AlltraCustomBridge.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/CommodityCCIPBridge.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/ISO4217WCCIPBridge.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/VaultBridgeAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/adapters/non-evm/AlgorandAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/adapters/non-evm/CosmosAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/adapters/non-evm/HederaAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/adapters/non-evm/SolanaAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/adapters/non-evm/TONAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/adapters/non-evm/TronAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/atomic/adapters/UniversalCcipAtomicSettlementAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/atomic/interfaces/IAtomicUnwindAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/bridge/modules/BridgeModuleRegistry.sol (100%) rename {contracts => archive/solidity/contracts}/ccip-integration/CCIPTxReporter.sol (100%) rename {contracts => archive/solidity/contracts}/ccip/CCIPRouterOptimized.sol (100%) rename {contracts => archive/solidity/contracts}/compliance/IndyVerifier.sol (100%) rename {contracts => archive/solidity/contracts}/config/ConfigurationRegistry.sol (100%) rename {contracts => archive/solidity/contracts}/dbis/DBIS_EIP712Lib.sol (100%) rename {contracts => archive/solidity/contracts}/interfaces/IAggregator.sol (100%) rename {contracts => archive/solidity/contracts}/liquidity/PoolManager.sol (100%) rename {contracts => archive/solidity/contracts}/nft/GRUFormulasNFT.sol (100%) rename {contracts => archive/solidity/contracts}/plugins/PluginRegistry.sol (100%) rename {contracts => archive/solidity/contracts}/registry/TruthNetworkAdapter.sol (100%) rename {contracts => archive/solidity/contracts}/registry/handlers/CommodityHandler.sol (100%) rename {contracts => archive/solidity/contracts}/registry/handlers/ERC20Handler.sol (100%) rename {contracts => archive/solidity/contracts}/registry/handlers/GRUHandler.sol (100%) rename {contracts => archive/solidity/contracts}/registry/handlers/ISO4217WHandler.sol (100%) rename {contracts => archive/solidity/contracts}/registry/handlers/SecurityHandler.sol (100%) rename {contracts => archive/solidity/contracts}/registry/interfaces/IAssetTypeHandler.sol (100%) rename {contracts => archive/solidity/contracts}/upgrades/ProxyFactory.sol (100%) rename {contracts => archive/solidity/contracts}/vault/BridgeVaultExtension.sol (100%) rename {contracts => archive/solidity/contracts}/vault/adapters/PMMPriceProvider.sol (100%) rename {contracts => archive/solidity/contracts}/vault/errors/VaultErrors.sol (100%) rename {contracts => archive/solidity/contracts}/vault/interfaces/IVaultStrategy.sol (100%) rename {contracts => archive/solidity/contracts}/vault/libraries/CurrencyValidation.sol (100%) rename {contracts => archive/solidity/contracts}/vault/libraries/MonetaryFormulas.sol (100%) rename {contracts => archive/solidity/contracts}/vault/libraries/XAUTriangulation.sol (100%) create mode 100644 contracts/flash/QuotePushTreasuryManager.sol create mode 100644 docs/architecture/FOUNDRY_MONOREPO_SCOPES.md create mode 100644 script/deploy/DeployQuotePushTreasuryManager.s.sol create mode 100644 script/flash/ManageQuotePushTreasuryManager.s.sol create mode 100644 script/flash/RunManagedMainnetAaveCwusdcUsdcQuotePushCycle.s.sol create mode 100644 script/flash/SweepAaveQuotePushFlashReceiverSurplus.s.sol rename {scripts => script}/tokenization/DeployTokenRegistry.s.sol (100%) rename {scripts => script}/tokenization/DeployTokenizedEUR.s.sol (100%) rename {scripts => script}/tokenization/RegisterToken.s.sol (100%) create mode 100755 scripts/forge/report-contract-reachability.py create mode 100755 scripts/forge/scope.sh create mode 100644 scripts/lib/forge-scope.sh create mode 100644 test/flash/AaveQuotePushFlashReceiver.t.sol create mode 100644 test/flash/QuotePushTreasuryManager.t.sol diff --git a/COMPLETE_MULTI_CHAIN_DEPLOYMENT.md b/COMPLETE_MULTI_CHAIN_DEPLOYMENT.md index bb6701f..a22ce44 100644 --- a/COMPLETE_MULTI_CHAIN_DEPLOYMENT.md +++ b/COMPLETE_MULTI_CHAIN_DEPLOYMENT.md @@ -48,12 +48,12 @@ All requested components for multi-chain deployment have been **fully implemente |-------|---------|------|--------| | XRP Ledger | XRPLAdapter | `contracts/bridge/adapters/non-evm/XRPLAdapter.sol` | ✅ Complete | | Stellar | StellarAdapter | `contracts/bridge/adapters/non-evm/StellarAdapter.sol` | ✅ Complete | -| Algorand | AlgorandAdapter | `contracts/bridge/adapters/non-evm/AlgorandAdapter.sol` | ✅ Complete | -| Hedera | HederaAdapter | `contracts/bridge/adapters/non-evm/HederaAdapter.sol` | ✅ Complete | -| Tron | TronAdapter | `contracts/bridge/adapters/non-evm/TronAdapter.sol` | ✅ Complete | -| TON | TONAdapter | `contracts/bridge/adapters/non-evm/TONAdapter.sol` | ✅ Complete | -| Cosmos | CosmosAdapter | `contracts/bridge/adapters/non-evm/CosmosAdapter.sol` | ✅ Complete | -| Solana | SolanaAdapter | `contracts/bridge/adapters/non-evm/SolanaAdapter.sol` | ✅ Complete | +| Algorand | AlgorandAdapter | `archive/solidity/contracts/bridge/adapters/non-evm/AlgorandAdapter.sol` | ✅ Complete (historical, archived) | +| Hedera | HederaAdapter | `archive/solidity/contracts/bridge/adapters/non-evm/HederaAdapter.sol` | ✅ Complete (historical, archived) | +| Tron | TronAdapter | `archive/solidity/contracts/bridge/adapters/non-evm/TronAdapter.sol` | ✅ Complete (historical, archived) | +| TON | TONAdapter | `archive/solidity/contracts/bridge/adapters/non-evm/TONAdapter.sol` | ✅ Complete (historical, archived) | +| Cosmos | CosmosAdapter | `archive/solidity/contracts/bridge/adapters/non-evm/CosmosAdapter.sol` | ✅ Complete (historical, archived) | +| Solana | SolanaAdapter | `archive/solidity/contracts/bridge/adapters/non-evm/SolanaAdapter.sol` | ✅ Complete (historical, archived) | ### **4. Hyperledger Adapters** ✅ (4 adapters) @@ -62,7 +62,7 @@ All requested components for multi-chain deployment have been **fully implemente | Firefly | FireflyAdapter | `contracts/bridge/adapters/hyperledger/FireflyAdapter.sol` | ✅ Complete | | Cacti | CactiAdapter | `contracts/bridge/adapters/hyperledger/CactiAdapter.sol` | ✅ Complete | | Fabric | FabricAdapter | `contracts/bridge/adapters/hyperledger/FabricAdapter.sol` | ✅ Complete | -| Indy | IndyVerifier | `contracts/compliance/IndyVerifier.sol` | ✅ Complete | +| Indy | IndyVerifier | `archive/solidity/contracts/compliance/IndyVerifier.sol` | ✅ Complete | ### **5. Service Integrations** ✅ diff --git a/IMPLEMENTATION_REPORT.md b/IMPLEMENTATION_REPORT.md index 02a617a..58d22b7 100644 --- a/IMPLEMENTATION_REPORT.md +++ b/IMPLEMENTATION_REPORT.md @@ -30,23 +30,23 @@ Successfully implemented a **production-grade, infinitely extensible cross-chain ### ✅ Phase 2: Bridge Infrastructure (3/3 complete) 5. ✅ UniversalCCIPBridge - Main bridge with PMM/vault integration -6. ✅ Specialized Bridges - 4 bridges (GRU, ISO4217W, Security, Commodity) +6. ✅ Specialized Bridges - 4 bridges (GRU, ISO4217W, Security, Commodity); ISO4217W and Commodity variants are now historical and archived 7. ✅ BridgeOrchestrator - Asset-type routing ### ✅ Phase 3: Liquidity (3/3 complete) 8. ✅ LiquidityManager - Multi-provider orchestration 9. ✅ DODOPMMProvider - DODO wrapper with ILiquidityProvider -10. ✅ PoolManager - Auto-pool creation +10. ✅ PoolManager - Auto-pool creation (historical, now archived) ### ✅ Phase 4: Extensibility (4/4 complete) -11. ✅ PluginRegistry - Register handlers, providers, modules -12. ✅ ProxyFactory - Deploy UUPS/Beacon proxies -13. ✅ ConfigurationRegistry - Runtime configuration -14. ✅ BridgeModuleRegistry - Pre/post hooks, validators +11. ✅ PluginRegistry - Register handlers, providers, modules (historical, now archived) +12. ✅ ProxyFactory - Deploy UUPS/Beacon proxies (historical, now archived) +13. ✅ ConfigurationRegistry - Runtime configuration (historical, now archived) +14. ✅ BridgeModuleRegistry - Pre/post hooks, validators (historical, now archived) ### ✅ Phase 5: Vault Integration (2/2 complete) -15. ✅ VaultBridgeAdapter - Vault-bridge interface -16. ✅ BridgeVaultExtension - Operation tracking +15. ✅ VaultBridgeAdapter - Vault-bridge interface (historical, now archived) +16. ✅ BridgeVaultExtension - Operation tracking (historical, now archived) ### ✅ Phase 6: Testing & Security (4/4 complete) 17. ✅ Integration tests - Full end-to-end flows @@ -68,15 +68,17 @@ Successfully implemented a **production-grade, infinitely extensible cross-chain ### Core Registry (7 contracts) ``` contracts/registry/ -├── UniversalAssetRegistry.sol (272 lines) +└── UniversalAssetRegistry.sol (272 lines) + +archive/solidity/contracts/registry/ ├── interfaces/ -│ └── IAssetTypeHandler.sol +│ └── IAssetTypeHandler.sol (historical, archived) └── handlers/ - ├── ERC20Handler.sol - ├── GRUHandler.sol - ├── ISO4217WHandler.sol - ├── SecurityHandler.sol - └── CommodityHandler.sol + ├── ERC20Handler.sol (archived) + ├── GRUHandler.sol (archived) + ├── ISO4217WHandler.sol (archived) + ├── SecurityHandler.sol (archived) + └── CommodityHandler.sol (archived) ``` ### Governance (3 contracts) @@ -93,44 +95,46 @@ contracts/sync/ contracts/bridge/ ├── UniversalCCIPBridge.sol (258 lines) ├── GRUCCIPBridge.sol (110 lines) -├── ISO4217WCCIPBridge.sol (140 lines) +├── ISO4217WCCIPBridge.sol (140 lines, archived) ├── SecurityCCIPBridge.sol (175 lines) -├── CommodityCCIPBridge.sol (200 lines) +├── CommodityCCIPBridge.sol (200 lines, archived) ├── BridgeOrchestrator.sol (180 lines) -├── VaultBridgeAdapter.sol (120 lines) +├── VaultBridgeAdapter.sol (120 lines, archived) └── modules/ - └── BridgeModuleRegistry.sol (185 lines) + └── BridgeModuleRegistry.sol (185 lines, archived) ``` ### Liquidity (4 contracts) ``` contracts/liquidity/ ├── LiquidityManager.sol (220 lines) -├── PoolManager.sol (190 lines) ├── interfaces/ │ └── ILiquidityProvider.sol └── providers/ └── DODOPMMProvider.sol (160 lines) + +archive/solidity/contracts/liquidity/ +└── PoolManager.sol (190 lines, historical, archived) ``` ### Extensibility (3 contracts) ``` -contracts/plugins/ -└── PluginRegistry.sol (155 lines) +archive/solidity/contracts/plugins/ +└── PluginRegistry.sol (155 lines, historical, archived) -contracts/upgrades/ -└── ProxyFactory.sol (145 lines) +archive/solidity/contracts/upgrades/ +└── ProxyFactory.sol (145 lines, archived) -contracts/config/ -└── ConfigurationRegistry.sol (110 lines) +archive/solidity/contracts/config/ +└── ConfigurationRegistry.sol (110 lines, archived) ``` ### Vault (2 contracts) ``` -contracts/vault/ -├── BridgeVaultExtension.sol (130 lines) +archive/solidity/contracts/vault/ +├── BridgeVaultExtension.sol (130 lines, archived) └── interfaces/ - └── IVaultStrategy.sol + └── IVaultStrategy.sol (archived) ``` **Total**: 30+ smart contracts @@ -198,7 +202,7 @@ script/deploy/ ### 1. Plugin Architecture ✅ ```solidity -// Add new asset type: +// Historical plugin architecture: pluginRegistry.registerPlugin( PluginType.AssetTypeHandler, "NewAssetType", diff --git a/Makefile b/Makefile index 01da329..0e28d12 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ help: @echo " make clean - Clean up temporary files" @echo " make genesis - Generate genesis file" @echo " make keys - Generate validator and oracle keys" - @echo " make contracts - Compile and test contracts" + @echo " make contracts - Compile and test contracts (optional: SCOPE=treasury, SCOPE=bridge/trustless, ...)" @echo " make monitoring - Deploy monitoring stack" @echo " make assets - Setup and download Azure icons (see Makefile.assets)" @@ -204,10 +204,11 @@ azure-login: test: @echo "Running tests (parallel)..." + @if [ -n "$(SCOPE)" ]; then echo "Forge scope: $(SCOPE)"; else echo "Forge scope: full"; fi @if [ -f .env ]; then \ - source .env && forge test --fork-url "$$RPC_URL" -j $$(nproc) || forge test -j $$(nproc); \ + source .env && FORGE_SCOPE="$(SCOPE)" bash scripts/forge/scope.sh test --fork-url "$$RPC_URL" -j $$(nproc) || FORGE_SCOPE="$(SCOPE)" bash scripts/forge/scope.sh test -j $$(nproc); \ else \ - forge test -j $$(nproc); \ + FORGE_SCOPE="$(SCOPE)" bash scripts/forge/scope.sh test -j $$(nproc); \ fi @./tests/health-check.sh & @HEALTH_PID=$$!; \ @@ -233,15 +234,15 @@ keys: contracts: @echo "Compiling contracts..." - forge build + @if [ -n "$(SCOPE)" ]; then echo "Forge scope: $(SCOPE)"; else echo "Forge scope: full"; fi + FORGE_SCOPE="$(SCOPE)" bash scripts/forge/scope.sh build @echo "Running contract tests (parallel)..." @if [ -f .env ]; then \ - source .env && forge test --fork-url "$$RPC_URL" -j $$(nproc) || forge test -j $$(nproc); \ + source .env && FORGE_SCOPE="$(SCOPE)" bash scripts/forge/scope.sh test --fork-url "$$RPC_URL" -j $$(nproc) || FORGE_SCOPE="$(SCOPE)" bash scripts/forge/scope.sh test -j $$(nproc); \ else \ - forge test -j $$(nproc); \ + FORGE_SCOPE="$(SCOPE)" bash scripts/forge/scope.sh test -j $$(nproc); \ fi monitoring: @echo "Deploying monitoring stack..." kubectl apply -f monitoring/k8s/prometheus.yaml - diff --git a/README.md b/README.md index 7f05fdf..6a900d3 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ > **Note**: 30 deployment and integration tasks remain (operational procedures, external submissions). All code tasks are 100% complete. See [Next Steps](docs/operations/tasks/NEXT_STEPS_LIST.md) for deployment tasks. > -> **Dependency Status**: Hybrid approach implemented - OpenZeppelin v4.9.6 installed (compatible with Solidity 0.8.19). New WETH contracts (WETH10, CCIPWETH9Bridge, CCIPWETH10Bridge) are independent and don't require OpenZeppelin. Existing contracts (CCIPSender, CCIPRouter, CCIPRouterOptimized, MultiSig, Voting) use OpenZeppelin. All contracts compile successfully. See [Hybrid Approach Implementation](docs/guides/HYBRID_APPROACH_IMPLEMENTATION.md) and [Dependencies Guide](docs/guides/DEPENDENCIES.md) for details. +> **Dependency Status**: Hybrid approach implemented - OpenZeppelin v4.9.6 installed (compatible with Solidity 0.8.19). New WETH contracts (WETH10, CCIPWETH9Bridge, CCIPWETH10Bridge) are independent and don't require OpenZeppelin. Active OpenZeppelin-dependent contracts include CCIPSender, CCIPRouter, MultiSig, and Voting; the historical `CCIPRouterOptimized` source now lives under `archive/solidity/contracts/ccip/`. See [Hybrid Approach Implementation](docs/guides/HYBRID_APPROACH_IMPLEMENTATION.md) and [Dependencies Guide](docs/guides/DEPENDENCIES.md) for details. --- diff --git a/UNIVERSAL_BRIDGE_IMPLEMENTATION_COMPLETE.md b/UNIVERSAL_BRIDGE_IMPLEMENTATION_COMPLETE.md index 7a945aa..249b7d2 100644 --- a/UNIVERSAL_BRIDGE_IMPLEMENTATION_COMPLETE.md +++ b/UNIVERSAL_BRIDGE_IMPLEMENTATION_COMPLETE.md @@ -23,25 +23,25 @@ The Universal Cross-Chain Asset Hub has been **fully implemented** according to ### Phase 2: Bridge Infrastructure ✅ - ✅ UniversalCCIPBridge - Main bridge supporting all assets - ✅ GRUCCIPBridge - GRU layer conversions -- ✅ ISO4217WCCIPBridge - eMoney/CBDC compliance +- ✅ ISO4217WCCIPBridge - eMoney/CBDC compliance (historical, now archived) - ✅ SecurityCCIPBridge - Securities with accreditation -- ✅ CommodityCCIPBridge - Commodity certificates +- ✅ CommodityCCIPBridge - Commodity certificates (historical, now archived) - ✅ BridgeOrchestrator - Asset-type routing ### Phase 3: Liquidity Integration ✅ - ✅ LiquidityManager - Multi-provider orchestration - ✅ ILiquidityProvider interface - Pluggable providers - ✅ DODOPMMProvider - DODO PMM wrapper -- ✅ PoolManager - Auto-pool creation +- ✅ PoolManager - Auto-pool creation (historical, now archived) ### Phase 4: Extensibility ✅ -- ✅ PluginRegistry - Pluggable components +- ✅ PluginRegistry - Pluggable components (historical, now archived) - ✅ ProxyFactory - UUPS and Beacon proxies - ✅ ConfigurationRegistry - Runtime configuration -- ✅ BridgeModuleRegistry - Pre/post hooks +- ✅ BridgeModuleRegistry - Pre/post hooks (historical, now archived) ### Phase 5: Vault Integration ✅ -- ✅ VaultBridgeAdapter - Vault-bridge interface +- ✅ VaultBridgeAdapter - Vault-bridge interface (historical, now archived) - ✅ BridgeVaultExtension - Operation tracking - ✅ IVaultStrategy interface - Future strategy support @@ -101,7 +101,7 @@ The Universal Cross-Chain Asset Hub has been **fully implemented** according to **Registry & Governance** - `contracts/registry/UniversalAssetRegistry.sol` -- `contracts/registry/interfaces/IAssetTypeHandler.sol` +- `archive/solidity/contracts/registry/interfaces/IAssetTypeHandler.sol` - `contracts/registry/handlers/[ERC20, GRU, ISO4217W, Security, Commodity]Handler.sol` (5) - `contracts/governance/GovernanceController.sol` - `contracts/sync/TokenlistGovernanceSync.sol` @@ -110,23 +110,23 @@ The Universal Cross-Chain Asset Hub has been **fully implemented** according to - `contracts/bridge/UniversalCCIPBridge.sol` - `contracts/bridge/[GRU, ISO4217W, Security, Commodity]CCIPBridge.sol` (4) - `contracts/bridge/BridgeOrchestrator.sol` -- `contracts/bridge/VaultBridgeAdapter.sol` -- `contracts/bridge/modules/BridgeModuleRegistry.sol` +- `archive/solidity/contracts/bridge/VaultBridgeAdapter.sol` +- `archive/solidity/contracts/bridge/modules/BridgeModuleRegistry.sol` **Liquidity** - `contracts/liquidity/LiquidityManager.sol` -- `contracts/liquidity/PoolManager.sol` +- `archive/solidity/contracts/liquidity/PoolManager.sol` - `contracts/liquidity/interfaces/ILiquidityProvider.sol` - `contracts/liquidity/providers/DODOPMMProvider.sol` **Extensibility** -- `contracts/plugins/PluginRegistry.sol` -- `contracts/upgrades/ProxyFactory.sol` -- `contracts/config/ConfigurationRegistry.sol` +- `archive/solidity/contracts/plugins/PluginRegistry.sol` +- `archive/solidity/contracts/upgrades/ProxyFactory.sol` +- `archive/solidity/contracts/config/ConfigurationRegistry.sol` **Vault** -- `contracts/vault/BridgeVaultExtension.sol` -- `contracts/vault/interfaces/IVaultStrategy.sol` +- `archive/solidity/contracts/vault/BridgeVaultExtension.sol` +- `archive/solidity/contracts/vault/interfaces/IVaultStrategy.sol` ### Tests (5+ files) - `test/integration/UniversalBridge.t.sol` @@ -155,7 +155,7 @@ The Universal Cross-Chain Asset Hub has been **fully implemented** according to This implementation prevents "boxing in" through: ### 1. Plugin Architecture ✅ -Deploy new asset handler, register via PluginRegistry. **No core contract changes needed.** +Historical plugin model: deploy new asset handler, register via PluginRegistry. **No core contract changes needed.** ### 2. Upgradeable Contracts ✅ All contracts use UUPS proxies. **Upgrade logic without changing addresses.** diff --git a/archive/solidity/README.md b/archive/solidity/README.md new file mode 100644 index 0000000..73b6f3c --- /dev/null +++ b/archive/solidity/README.md @@ -0,0 +1,27 @@ +# Archived Solidity + +This directory holds Solidity files intentionally moved out of `contracts/` so +they are excluded from the default full-repo Foundry compile graph. + +Rules: + +- Only archive files after confirming they are unreachable from the repo's + current Solidity tests and scripts. +- Move files here in small batches and re-run the affected scoped Forge build + and test commands after each batch. +- Treat archive status as "kept for reference", not "safe to delete". + +Current archived batches in this repo include: + +- legacy bridge atomic settlement interfaces and adapters +- unused non-EVM bridge adapter implementations that are no longer referenced by + the active Solidity test and deployment graph +- historical bridge implementations such as `AlltraCustomBridge`, + `ISO4217WCCIPBridge`, `CommodityCCIPBridge`, `VaultBridgeAdapter`, and + `BridgeModuleRegistry` +- historical registry, vault, configuration, NFT, and proxy helper contracts + that are no longer reachable from the active Solidity deployment/test graph +- historical CCIP, compliance, liquidity, plugin, registry-interface, and vault + helper contracts such as `CCIPTxReporter`, `CCIPRouterOptimized`, + `IndyVerifier`, `PoolManager`, `PluginRegistry`, `IAssetTypeHandler`, and + `XAUTriangulation` diff --git a/contracts/bridge/AlltraCustomBridge.sol b/archive/solidity/contracts/bridge/AlltraCustomBridge.sol similarity index 100% rename from contracts/bridge/AlltraCustomBridge.sol rename to archive/solidity/contracts/bridge/AlltraCustomBridge.sol diff --git a/contracts/bridge/CommodityCCIPBridge.sol b/archive/solidity/contracts/bridge/CommodityCCIPBridge.sol similarity index 100% rename from contracts/bridge/CommodityCCIPBridge.sol rename to archive/solidity/contracts/bridge/CommodityCCIPBridge.sol diff --git a/contracts/bridge/ISO4217WCCIPBridge.sol b/archive/solidity/contracts/bridge/ISO4217WCCIPBridge.sol similarity index 100% rename from contracts/bridge/ISO4217WCCIPBridge.sol rename to archive/solidity/contracts/bridge/ISO4217WCCIPBridge.sol diff --git a/contracts/bridge/VaultBridgeAdapter.sol b/archive/solidity/contracts/bridge/VaultBridgeAdapter.sol similarity index 100% rename from contracts/bridge/VaultBridgeAdapter.sol rename to archive/solidity/contracts/bridge/VaultBridgeAdapter.sol diff --git a/contracts/bridge/adapters/non-evm/AlgorandAdapter.sol b/archive/solidity/contracts/bridge/adapters/non-evm/AlgorandAdapter.sol similarity index 100% rename from contracts/bridge/adapters/non-evm/AlgorandAdapter.sol rename to archive/solidity/contracts/bridge/adapters/non-evm/AlgorandAdapter.sol diff --git a/contracts/bridge/adapters/non-evm/CosmosAdapter.sol b/archive/solidity/contracts/bridge/adapters/non-evm/CosmosAdapter.sol similarity index 100% rename from contracts/bridge/adapters/non-evm/CosmosAdapter.sol rename to archive/solidity/contracts/bridge/adapters/non-evm/CosmosAdapter.sol diff --git a/contracts/bridge/adapters/non-evm/HederaAdapter.sol b/archive/solidity/contracts/bridge/adapters/non-evm/HederaAdapter.sol similarity index 100% rename from contracts/bridge/adapters/non-evm/HederaAdapter.sol rename to archive/solidity/contracts/bridge/adapters/non-evm/HederaAdapter.sol diff --git a/contracts/bridge/adapters/non-evm/SolanaAdapter.sol b/archive/solidity/contracts/bridge/adapters/non-evm/SolanaAdapter.sol similarity index 100% rename from contracts/bridge/adapters/non-evm/SolanaAdapter.sol rename to archive/solidity/contracts/bridge/adapters/non-evm/SolanaAdapter.sol diff --git a/contracts/bridge/adapters/non-evm/TONAdapter.sol b/archive/solidity/contracts/bridge/adapters/non-evm/TONAdapter.sol similarity index 100% rename from contracts/bridge/adapters/non-evm/TONAdapter.sol rename to archive/solidity/contracts/bridge/adapters/non-evm/TONAdapter.sol diff --git a/contracts/bridge/adapters/non-evm/TronAdapter.sol b/archive/solidity/contracts/bridge/adapters/non-evm/TronAdapter.sol similarity index 100% rename from contracts/bridge/adapters/non-evm/TronAdapter.sol rename to archive/solidity/contracts/bridge/adapters/non-evm/TronAdapter.sol diff --git a/contracts/bridge/atomic/adapters/UniversalCcipAtomicSettlementAdapter.sol b/archive/solidity/contracts/bridge/atomic/adapters/UniversalCcipAtomicSettlementAdapter.sol similarity index 100% rename from contracts/bridge/atomic/adapters/UniversalCcipAtomicSettlementAdapter.sol rename to archive/solidity/contracts/bridge/atomic/adapters/UniversalCcipAtomicSettlementAdapter.sol diff --git a/contracts/bridge/atomic/interfaces/IAtomicUnwindAdapter.sol b/archive/solidity/contracts/bridge/atomic/interfaces/IAtomicUnwindAdapter.sol similarity index 100% rename from contracts/bridge/atomic/interfaces/IAtomicUnwindAdapter.sol rename to archive/solidity/contracts/bridge/atomic/interfaces/IAtomicUnwindAdapter.sol diff --git a/contracts/bridge/modules/BridgeModuleRegistry.sol b/archive/solidity/contracts/bridge/modules/BridgeModuleRegistry.sol similarity index 100% rename from contracts/bridge/modules/BridgeModuleRegistry.sol rename to archive/solidity/contracts/bridge/modules/BridgeModuleRegistry.sol diff --git a/contracts/ccip-integration/CCIPTxReporter.sol b/archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol similarity index 100% rename from contracts/ccip-integration/CCIPTxReporter.sol rename to archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol diff --git a/contracts/ccip/CCIPRouterOptimized.sol b/archive/solidity/contracts/ccip/CCIPRouterOptimized.sol similarity index 100% rename from contracts/ccip/CCIPRouterOptimized.sol rename to archive/solidity/contracts/ccip/CCIPRouterOptimized.sol diff --git a/contracts/compliance/IndyVerifier.sol b/archive/solidity/contracts/compliance/IndyVerifier.sol similarity index 100% rename from contracts/compliance/IndyVerifier.sol rename to archive/solidity/contracts/compliance/IndyVerifier.sol diff --git a/contracts/config/ConfigurationRegistry.sol b/archive/solidity/contracts/config/ConfigurationRegistry.sol similarity index 100% rename from contracts/config/ConfigurationRegistry.sol rename to archive/solidity/contracts/config/ConfigurationRegistry.sol diff --git a/contracts/dbis/DBIS_EIP712Lib.sol b/archive/solidity/contracts/dbis/DBIS_EIP712Lib.sol similarity index 100% rename from contracts/dbis/DBIS_EIP712Lib.sol rename to archive/solidity/contracts/dbis/DBIS_EIP712Lib.sol diff --git a/contracts/interfaces/IAggregator.sol b/archive/solidity/contracts/interfaces/IAggregator.sol similarity index 100% rename from contracts/interfaces/IAggregator.sol rename to archive/solidity/contracts/interfaces/IAggregator.sol diff --git a/contracts/liquidity/PoolManager.sol b/archive/solidity/contracts/liquidity/PoolManager.sol similarity index 100% rename from contracts/liquidity/PoolManager.sol rename to archive/solidity/contracts/liquidity/PoolManager.sol diff --git a/contracts/nft/GRUFormulasNFT.sol b/archive/solidity/contracts/nft/GRUFormulasNFT.sol similarity index 100% rename from contracts/nft/GRUFormulasNFT.sol rename to archive/solidity/contracts/nft/GRUFormulasNFT.sol diff --git a/contracts/plugins/PluginRegistry.sol b/archive/solidity/contracts/plugins/PluginRegistry.sol similarity index 100% rename from contracts/plugins/PluginRegistry.sol rename to archive/solidity/contracts/plugins/PluginRegistry.sol diff --git a/contracts/registry/TruthNetworkAdapter.sol b/archive/solidity/contracts/registry/TruthNetworkAdapter.sol similarity index 100% rename from contracts/registry/TruthNetworkAdapter.sol rename to archive/solidity/contracts/registry/TruthNetworkAdapter.sol diff --git a/contracts/registry/handlers/CommodityHandler.sol b/archive/solidity/contracts/registry/handlers/CommodityHandler.sol similarity index 100% rename from contracts/registry/handlers/CommodityHandler.sol rename to archive/solidity/contracts/registry/handlers/CommodityHandler.sol diff --git a/contracts/registry/handlers/ERC20Handler.sol b/archive/solidity/contracts/registry/handlers/ERC20Handler.sol similarity index 100% rename from contracts/registry/handlers/ERC20Handler.sol rename to archive/solidity/contracts/registry/handlers/ERC20Handler.sol diff --git a/contracts/registry/handlers/GRUHandler.sol b/archive/solidity/contracts/registry/handlers/GRUHandler.sol similarity index 100% rename from contracts/registry/handlers/GRUHandler.sol rename to archive/solidity/contracts/registry/handlers/GRUHandler.sol diff --git a/contracts/registry/handlers/ISO4217WHandler.sol b/archive/solidity/contracts/registry/handlers/ISO4217WHandler.sol similarity index 100% rename from contracts/registry/handlers/ISO4217WHandler.sol rename to archive/solidity/contracts/registry/handlers/ISO4217WHandler.sol diff --git a/contracts/registry/handlers/SecurityHandler.sol b/archive/solidity/contracts/registry/handlers/SecurityHandler.sol similarity index 100% rename from contracts/registry/handlers/SecurityHandler.sol rename to archive/solidity/contracts/registry/handlers/SecurityHandler.sol diff --git a/contracts/registry/interfaces/IAssetTypeHandler.sol b/archive/solidity/contracts/registry/interfaces/IAssetTypeHandler.sol similarity index 100% rename from contracts/registry/interfaces/IAssetTypeHandler.sol rename to archive/solidity/contracts/registry/interfaces/IAssetTypeHandler.sol diff --git a/contracts/upgrades/ProxyFactory.sol b/archive/solidity/contracts/upgrades/ProxyFactory.sol similarity index 100% rename from contracts/upgrades/ProxyFactory.sol rename to archive/solidity/contracts/upgrades/ProxyFactory.sol diff --git a/contracts/vault/BridgeVaultExtension.sol b/archive/solidity/contracts/vault/BridgeVaultExtension.sol similarity index 100% rename from contracts/vault/BridgeVaultExtension.sol rename to archive/solidity/contracts/vault/BridgeVaultExtension.sol diff --git a/contracts/vault/adapters/PMMPriceProvider.sol b/archive/solidity/contracts/vault/adapters/PMMPriceProvider.sol similarity index 100% rename from contracts/vault/adapters/PMMPriceProvider.sol rename to archive/solidity/contracts/vault/adapters/PMMPriceProvider.sol diff --git a/contracts/vault/errors/VaultErrors.sol b/archive/solidity/contracts/vault/errors/VaultErrors.sol similarity index 100% rename from contracts/vault/errors/VaultErrors.sol rename to archive/solidity/contracts/vault/errors/VaultErrors.sol diff --git a/contracts/vault/interfaces/IVaultStrategy.sol b/archive/solidity/contracts/vault/interfaces/IVaultStrategy.sol similarity index 100% rename from contracts/vault/interfaces/IVaultStrategy.sol rename to archive/solidity/contracts/vault/interfaces/IVaultStrategy.sol diff --git a/contracts/vault/libraries/CurrencyValidation.sol b/archive/solidity/contracts/vault/libraries/CurrencyValidation.sol similarity index 100% rename from contracts/vault/libraries/CurrencyValidation.sol rename to archive/solidity/contracts/vault/libraries/CurrencyValidation.sol diff --git a/contracts/vault/libraries/MonetaryFormulas.sol b/archive/solidity/contracts/vault/libraries/MonetaryFormulas.sol similarity index 100% rename from contracts/vault/libraries/MonetaryFormulas.sol rename to archive/solidity/contracts/vault/libraries/MonetaryFormulas.sol diff --git a/contracts/vault/libraries/XAUTriangulation.sol b/archive/solidity/contracts/vault/libraries/XAUTriangulation.sol similarity index 100% rename from contracts/vault/libraries/XAUTriangulation.sol rename to archive/solidity/contracts/vault/libraries/XAUTriangulation.sol diff --git a/contracts/dbis/BUILD_NOTES.md b/contracts/dbis/BUILD_NOTES.md index ee100ba..ec1067b 100644 --- a/contracts/dbis/BUILD_NOTES.md +++ b/contracts/dbis/BUILD_NOTES.md @@ -3,7 +3,7 @@ - **Contracts:** All DBIS Rail contracts (RootRegistry, ParticipantRegistry, SignerRegistry, SettlementRouter, GRU_MintController, StablecoinReferenceRegistry, Conversion Router) are in this folder and implement Technical Spec v1 and v1.5 add-ons. - **Tests:** `test/dbis/DBIS_Rail.t.sol` covers submitMintAuth success, replay revert, and signer-revoked-at-block. Uses `MockMintableToken` for a minimal GRU token in tests. - **Build:** Default Foundry config (`via_ir = true`, `optimizer_runs = 200`) builds successfully. Yul stack-too-deep was resolved by: - - Moving EIP-712 hashing and signature recovery into `DBIS_EIP712Helper` (and optional `DBIS_EIP712Lib`). + - Moving EIP-712 hashing and signature recovery into `DBIS_EIP712Helper` (and optional historical `DBIS_EIP712Lib`, now archived at `archive/solidity/contracts/dbis/DBIS_EIP712Lib.sol`). - Extracting the mint loop in `DBIS_GRU_MintController.mintFromAuthorization` into `_mintToRecipients` to reduce stack depth. - Using `StablecoinReferenceRegistry._setEntry` for struct assignment and `SignerRegistry.hasDuplicateSigners` / `areSignersActiveAtBlock` to keep router loops out of the main path. - **Deploy:** Run `DeployDBISRail.s.sol` on Chain 138; deploy `DBIS_EIP712Helper` first and pass its address to both `DBIS_SettlementRouter` and `DBIS_ConversionRouter` constructors; then set GRU token on MintController, grant MINTER_ROLE on c* tokens to MintController, register stablecoins, and add venues/quote issuers as needed. diff --git a/contracts/flash/AaveQuotePushFlashReceiver.sol b/contracts/flash/AaveQuotePushFlashReceiver.sol index be9d317..8d3ecfa 100644 --- a/contracts/flash/AaveQuotePushFlashReceiver.sol +++ b/contracts/flash/AaveQuotePushFlashReceiver.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -85,7 +86,7 @@ interface IAaveAtomicBridgeCoordinator { * @notice Aave V3 flash-loan receiver for the quote-push workflow: * flash borrow quote (`flashLoan` single-asset) -> buy PMM base -> unwind base externally -> repay lender, retaining any surplus. */ -contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashLoanReceiver { +contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashLoanReceiver, Ownable { using SafeERC20 for IERC20; address public immutable pool; @@ -120,6 +121,7 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL error BadParams(); error InsufficientToRepay(); error InvalidAtomicBridge(); + error NothingToSweep(); event QuotePushExecuted( address indexed quoteToken, @@ -137,8 +139,11 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL uint256 bridgeAmount, uint256 minDestinationAmount ); + event TokenSwept(address indexed token, address indexed to, uint256 amount); + event SurplusSwept(address indexed token, address indexed to, uint256 amount, uint256 reserveRetained); - constructor(address pool_) { + constructor(address pool_, address initialOwner) Ownable(initialOwner) { + if (pool_ == address(0) || initialOwner == address(0)) revert BadParams(); pool = pool_; } @@ -155,6 +160,31 @@ contract AaveQuotePushFlashReceiver is IAaveFlashLoanSimpleReceiver, IAaveFlashL ); } + function quoteSurplusBalance(address quoteToken, uint256 reserveRetained) public view returns (uint256 surplus) { + uint256 quoteBal = IERC20(quoteToken).balanceOf(address(this)); + if (quoteBal > reserveRetained) { + surplus = quoteBal - reserveRetained; + } + } + + function sweepQuoteSurplus(address quoteToken, address to, uint256 reserveRetained) + external + onlyOwner + returns (uint256 amount) + { + if (quoteToken == address(0) || to == address(0)) revert BadParams(); + amount = quoteSurplusBalance(quoteToken, reserveRetained); + if (amount == 0) revert NothingToSweep(); + IERC20(quoteToken).safeTransfer(to, amount); + emit SurplusSwept(quoteToken, to, amount, reserveRetained); + } + + function sweepToken(address token, address to, uint256 amount) external onlyOwner { + if (token == address(0) || to == address(0) || amount == 0) revert BadParams(); + IERC20(token).safeTransfer(to, amount); + emit TokenSwept(token, to, amount); + } + function executeOperation( address[] calldata assets, uint256[] calldata amounts, diff --git a/contracts/flash/QuotePushTreasuryManager.sol b/contracts/flash/QuotePushTreasuryManager.sol new file mode 100644 index 0000000..a35327c --- /dev/null +++ b/contracts/flash/QuotePushTreasuryManager.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +interface IQuotePushSweepableReceiver { + function owner() external view returns (address); + function quoteSurplusBalance(address quoteToken, uint256 reserveRetained) external view returns (uint256 surplus); + function sweepQuoteSurplus(address quoteToken, address to, uint256 reserveRetained) + external + returns (uint256 amount); +} + +/** + * @title QuotePushTreasuryManager + * @notice Minimal treasury manager for Aave quote-push retained surplus. + * Intended flow: + * 1. Receiver retains quote surplus after flash repayment. + * 2. This manager, as receiver owner, harvests that surplus into itself. + * 3. Owner/operator distributes quote to gas and recycle recipients. + * + * Gas replenishment is still an operator policy in quote units; converting + * quote into native gas token remains off-chain / external. + */ +contract QuotePushTreasuryManager is Ownable { + using SafeERC20 for IERC20; + + IQuotePushSweepableReceiver public immutable receiver; + IERC20 public immutable quoteToken; + + address public operator; + address public gasRecipient; + address public recycleRecipient; + uint256 public receiverReserveRetained; + uint256 public managerReserveRetained; + + error BadConfig(); + error Unauthorized(); + error NothingToHarvest(); + error InsufficientAvailable(uint256 available, uint256 requested); + + event OperatorUpdated(address indexed previousOperator, address indexed newOperator); + event RecipientsUpdated(address indexed gasRecipient, address indexed recycleRecipient); + event ReservesUpdated(uint256 receiverReserveRetained, uint256 managerReserveRetained); + event ReceiverSurplusHarvested(address indexed token, uint256 amount, uint256 receiverReserveRetained); + event QuoteDistributed(address indexed token, address indexed to, uint256 amount, bytes32 purpose); + event TokenRescued(address indexed token, address indexed to, uint256 amount); + + modifier onlyOwnerOrOperator() { + if (msg.sender != owner() && msg.sender != operator) revert Unauthorized(); + _; + } + + constructor( + address initialOwner, + address receiver_, + address quoteToken_, + address operator_, + address gasRecipient_, + address recycleRecipient_, + uint256 receiverReserveRetained_, + uint256 managerReserveRetained_ + ) Ownable(initialOwner) { + if ( + initialOwner == address(0) || receiver_ == address(0) || quoteToken_ == address(0) + || gasRecipient_ == address(0) || recycleRecipient_ == address(0) + ) revert BadConfig(); + + receiver = IQuotePushSweepableReceiver(receiver_); + quoteToken = IERC20(quoteToken_); + operator = operator_; + gasRecipient = gasRecipient_; + recycleRecipient = recycleRecipient_; + receiverReserveRetained = receiverReserveRetained_; + managerReserveRetained = managerReserveRetained_; + } + + function receiverOwner() public view returns (address) { + return receiver.owner(); + } + + function isReceiverOwnedByManager() public view returns (bool) { + return receiver.owner() == address(this); + } + + function quoteBalance() public view returns (uint256) { + return quoteToken.balanceOf(address(this)); + } + + function availableQuote() public view returns (uint256 available) { + uint256 balance = quoteBalance(); + if (balance > managerReserveRetained) { + available = balance - managerReserveRetained; + } + } + + function receiverSweepableQuote() public view returns (uint256) { + return receiver.quoteSurplusBalance(address(quoteToken), receiverReserveRetained); + } + + function setOperator(address newOperator) external onlyOwner { + emit OperatorUpdated(operator, newOperator); + operator = newOperator; + } + + function setRecipients(address gasRecipient_, address recycleRecipient_) external onlyOwner { + if (gasRecipient_ == address(0) || recycleRecipient_ == address(0)) revert BadConfig(); + gasRecipient = gasRecipient_; + recycleRecipient = recycleRecipient_; + emit RecipientsUpdated(gasRecipient_, recycleRecipient_); + } + + function setReserves(uint256 receiverReserveRetained_, uint256 managerReserveRetained_) external onlyOwner { + receiverReserveRetained = receiverReserveRetained_; + managerReserveRetained = managerReserveRetained_; + emit ReservesUpdated(receiverReserveRetained_, managerReserveRetained_); + } + + function harvestReceiverSurplus() public onlyOwnerOrOperator returns (uint256 amount) { + amount = receiver.sweepQuoteSurplus(address(quoteToken), address(this), receiverReserveRetained); + if (amount == 0) revert NothingToHarvest(); + emit ReceiverSurplusHarvested(address(quoteToken), amount, receiverReserveRetained); + } + + function distributeQuote(address to, uint256 amount, bytes32 purpose) external onlyOwnerOrOperator { + _distributeQuote(to, amount, purpose); + } + + function distributeToConfiguredRecipients(uint256 gasAmount, uint256 recycleAmount) external onlyOwnerOrOperator { + uint256 requested = gasAmount + recycleAmount; + _requireAvailable(requested); + + if (gasAmount > 0) { + quoteToken.safeTransfer(gasRecipient, gasAmount); + emit QuoteDistributed(address(quoteToken), gasRecipient, gasAmount, bytes32("gas")); + } + if (recycleAmount > 0) { + quoteToken.safeTransfer(recycleRecipient, recycleAmount); + emit QuoteDistributed(address(quoteToken), recycleRecipient, recycleAmount, bytes32("recycle")); + } + } + + function rescueToken(address token, address to, uint256 amount) external onlyOwner { + if (token == address(0) || to == address(0) || amount == 0) revert BadConfig(); + if (token == address(quoteToken)) { + _requireAvailable(amount); + } + IERC20(token).safeTransfer(to, amount); + emit TokenRescued(token, to, amount); + } + + function _distributeQuote(address to, uint256 amount, bytes32 purpose) internal { + if (to == address(0) || amount == 0) revert BadConfig(); + _requireAvailable(amount); + quoteToken.safeTransfer(to, amount); + emit QuoteDistributed(address(quoteToken), to, amount, purpose); + } + + function _requireAvailable(uint256 requested) internal view { + uint256 available = availableQuote(); + if (requested > available) revert InsufficientAvailable(available, requested); + } +} diff --git a/docs/E2E_TESTING_AND_DEPLOYMENT_STATUS.md b/docs/E2E_TESTING_AND_DEPLOYMENT_STATUS.md index 5d377ef..57760c6 100644 --- a/docs/E2E_TESTING_AND_DEPLOYMENT_STATUS.md +++ b/docs/E2E_TESTING_AND_DEPLOYMENT_STATUS.md @@ -77,7 +77,7 @@ - Dependencies: None (if custom router) - Status: **NOT DEPLOYED** -10. ⏳ **CCIPRouterOptimized** (`contracts/ccip/CCIPRouterOptimized.sol`) +10. ⏳ **CCIPRouterOptimized** (`archive/solidity/contracts/ccip/CCIPRouterOptimized.sol`) - Script: None (may need creation) - Dependencies: Unknown - Status: **NOT DEPLOYED** (no script found) diff --git a/docs/MASTER_CONTRACTS_AND_INFRASTRUCTURE_LIST.md b/docs/MASTER_CONTRACTS_AND_INFRASTRUCTURE_LIST.md index 11acba9..937515e 100644 --- a/docs/MASTER_CONTRACTS_AND_INFRASTRUCTURE_LIST.md +++ b/docs/MASTER_CONTRACTS_AND_INFRASTRUCTURE_LIST.md @@ -16,8 +16,8 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | **CCIPWETH10Bridge** | `contracts/ccip/CCIPWETH10Bridge.sol` | Cross-chain bridge for WETH10 via CCIP. | | **UniversalCCIPBridge** | `contracts/bridge/UniversalCCIPBridge.sol` | Base CCIP bridge logic; extended by token-specific bridges. | | **GRUCCIPBridge** | `contracts/bridge/GRUCCIPBridge.sol` | CCIP bridge for GRU (Global Reserve Unit) tokens. | -| **ISO4217WCCIPBridge** | `contracts/bridge/ISO4217WCCIPBridge.sol` | CCIP bridge for ISO-4217 W tokens. | -| **CommodityCCIPBridge** | `contracts/bridge/CommodityCCIPBridge.sol` | CCIP bridge for commodity-backed tokens. | +| **ISO4217WCCIPBridge** | `archive/solidity/contracts/bridge/ISO4217WCCIPBridge.sol` | Historical CCIP bridge for ISO-4217 W tokens; archived out of the active compile graph. | +| **CommodityCCIPBridge** | `archive/solidity/contracts/bridge/CommodityCCIPBridge.sol` | Historical CCIP bridge for commodity-backed tokens; archived out of the active compile graph. | **Typical .env:** `CCIP_ROUTER`, `CCIPWETH9_BRIDGE_*`, `CCIPWETH10_BRIDGE_*`, `*_SELECTOR`, `LINK_TOKEN`, per chain. @@ -42,13 +42,13 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | Contract | Path | Purpose | |----------|------|---------| -| **AlltraCustomBridge** | `contracts/bridge/AlltraCustomBridge.sol` | Alltra transport for custom bridge messaging. | +| **AlltraCustomBridge** | `archive/solidity/contracts/bridge/AlltraCustomBridge.sol` | Historical Alltra transport for custom bridge messaging; archived out of the active compile graph. | | **EtherlinkRelayReceiver** | `contracts/bridge/EtherlinkRelayReceiver.sol` | Receives relayed messages (e.g. Etherlink). | | **BridgeRegistry** | `contracts/bridge/interop/BridgeRegistry.sol` | Registry of tokens and routes for bridge operations. | | **BridgeEscrowVault** | `contracts/bridge/interop/BridgeEscrowVault.sol` | Escrow for bridge-in/bridge-out flows. | | **BridgeVerifier** | `contracts/bridge/interop/BridgeVerifier.sol` | Verification of bridge messages (e.g. EIP-712). | | **MintBurnController** | `contracts/bridge/interop/MintBurnController.sol` | Mint/burn control for bridged tokens. | -| **VaultBridgeAdapter** | `contracts/bridge/VaultBridgeAdapter.sol` | Adapter for vault ↔ bridge. | +| **VaultBridgeAdapter** | `archive/solidity/contracts/bridge/VaultBridgeAdapter.sol` | Historical vault ↔ bridge adapter; archived out of the active compile graph. | | **BridgeOrchestrator** | `contracts/bridge/BridgeOrchestrator.sol` | Orchestrates multi-bridge flows. | --- @@ -61,7 +61,7 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | **SwapRouter** | `contracts/bridge/trustless/SwapRouter.sol` | Basic swap router (trustless bridge context). | | **EnhancedSwapRouter** | `contracts/bridge/trustless/EnhancedSwapRouter.sol` | Aggregates Uniswap V3, Dodoex, Curve, Balancer, 1inch for swap+bridge+swap. | | **CCIPRouter** | `contracts/ccip/CCIPRouter.sol` | Optional custom router logic (project-specific). | -| **CCIPRouterOptimized** | `contracts/ccip/CCIPRouterOptimized.sol` | Optimized fee/router variant. | +| **CCIPRouterOptimized** | `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` | Historical optimized fee/router variant; archived out of the active compile graph. | **Typical .env:** `SWAP_ROUTER`, `ENHANCED_SWAP_ROUTER`, `UNISWAP_V3_ROUTER`, `DODOEX_ROUTER`, `CURVE_3POOL`, `BALANCER_VAULT`, `ONEINCH_ROUTER`. @@ -79,7 +79,7 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | **Aggregator** | `contracts/oracle/Aggregator.sol` | Chainlink-compatible price aggregator (on-chain). | | **Proxy** | `contracts/oracle/Proxy.sol` | Oracle proxy (consumer-facing). | | **OracleWithCCIP** | `contracts/oracle/OracleWithCCIP.sol` | Oracle that uses CCIP for cross-chain data. | -| **PMMPriceProvider** | `contracts/vault/adapters/PMMPriceProvider.sol` | Returns asset price in quote token from DODO PMM (oracle-backed when ReserveSystem set). | +| **PMMPriceProvider** | `archive/solidity/contracts/vault/adapters/PMMPriceProvider.sol` | Historical asset price provider in quote token from DODO PMM; archived out of the active compile graph. | **Typical .env:** `ORACLE_AGGREGATOR_ADDRESS`, `ORACLE_PROXY_ADDRESS`, `RESERVE_SYSTEM`, `ORACLE_PRICE_FEED`, `RPC_URL_138`. See `docs/integration/ORACLE_AND_KEEPER_CHAIN138.md`. @@ -102,22 +102,22 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r |----------|------|---------| | **ChainRegistry** | `contracts/registry/ChainRegistry.sol` | Registry of chains and chain-specific config. | | **UniversalAssetRegistry** | `contracts/registry/UniversalAssetRegistry.sol` | Registry of asset types and handlers (GRU, ISO4217W, Commodity, etc.). | -| **GRUHandler** | `contracts/registry/handlers/GRUHandler.sol` | Asset type handler for GRU. | -| **ISO4217WHandler** | `contracts/registry/handlers/ISO4217WHandler.sol` | Asset type handler for ISO-4217 W tokens. | -| **CommodityHandler** | `contracts/registry/handlers/CommodityHandler.sol` | Asset type handler for commodities. | -| **ERC20Handler** | `contracts/registry/handlers/ERC20Handler.sol` | Generic ERC20 handler. | -| **SecurityHandler** | `contracts/registry/handlers/SecurityHandler.sol` | Security-type asset handler. | +| **GRUHandler** | `archive/solidity/contracts/registry/handlers/GRUHandler.sol` | Historical asset type handler for GRU; archived out of the active compile graph. | +| **ISO4217WHandler** | `archive/solidity/contracts/registry/handlers/ISO4217WHandler.sol` | Historical asset type handler for ISO-4217 W tokens; archived out of the active compile graph. | +| **CommodityHandler** | `archive/solidity/contracts/registry/handlers/CommodityHandler.sol` | Historical asset type handler for commodities; archived out of the active compile graph. | +| **ERC20Handler** | `archive/solidity/contracts/registry/handlers/ERC20Handler.sol` | Historical generic ERC20 handler; archived out of the active compile graph. | +| **SecurityHandler** | `archive/solidity/contracts/registry/handlers/SecurityHandler.sol` | Historical security-type asset handler; archived out of the active compile graph. | | **BridgeRegistry** | `contracts/bridge/interop/BridgeRegistry.sol` | Registry of bridgeable tokens and routes. | -| **BridgeModuleRegistry** | `contracts/bridge/modules/BridgeModuleRegistry.sol` | Registry of bridge modules. | -| **ConfigurationRegistry** | `contracts/config/ConfigurationRegistry.sol` | System configuration registry. | -| **PluginRegistry** | `contracts/plugins/PluginRegistry.sol` | Plugin registration. | +| **BridgeModuleRegistry** | `archive/solidity/contracts/bridge/modules/BridgeModuleRegistry.sol` | Historical bridge module registry; archived out of the active compile graph. | +| **ConfigurationRegistry** | `archive/solidity/contracts/config/ConfigurationRegistry.sol` | Historical system configuration registry; archived out of the active compile graph. | +| **PluginRegistry** | `archive/solidity/contracts/plugins/PluginRegistry.sol` | Historical plugin registration flow; archived out of the active compile graph. | | **MirrorRegistry** | `contracts/mirror/MirrorRegistry.sol` | Mirror/duplicate contract registry. | | **PrivatePoolRegistry** | `contracts/dex/PrivatePoolRegistry.sol` | Registry of private (e.g. XAU-anchored) DODO pools. | | **VaultFactory** | `contracts/vault/VaultFactory.sol` | Creates Vault instances and associated tokens. | | **TokenFactory** (ISO4217W) | `contracts/iso4217w/TokenFactory.sol` | Creates ISO-4217 W tokens. | | **TokenRegistry** (ISO4217W) | `contracts/iso4217w/registry/TokenRegistry.sol` | Registry of W tokens by currency code. | | **TokenRegistry** (tokenization) | `contracts/tokenization/TokenRegistry.sol` | Generic token registry. | -| **ProxyFactory** | `contracts/upgrades/ProxyFactory.sol` | Creates upgradeable proxies. | +| **ProxyFactory** | `archive/solidity/contracts/upgrades/ProxyFactory.sol` | Historical upgradeable proxy factory; archived out of the active compile graph. | --- @@ -151,8 +151,8 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | **Liquidation** | `contracts/vault/Liquidation.sol` | Liquidation logic. | | **DepositToken** | `contracts/vault/tokens/DepositToken.sol` | Receipt token for collateral. | | **DebtToken** | `contracts/vault/tokens/DebtToken.sol` | Debt position token. | -| **PMMPriceProvider** | `contracts/vault/adapters/PMMPriceProvider.sol` | Optional PMM-based price for assets (vault/UI). | -| **BridgeVaultExtension** | `contracts/vault/BridgeVaultExtension.sol` | Vault extension for bridge flows. | +| **PMMPriceProvider** | `archive/solidity/contracts/vault/adapters/PMMPriceProvider.sol` | Historical PMM-based price provider for vault/UI use; archived out of the active compile graph. | +| **BridgeVaultExtension** | `archive/solidity/contracts/vault/BridgeVaultExtension.sol` | Historical vault extension for bridge flows; archived out of the active compile graph. | --- @@ -164,7 +164,7 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | **DODOPMMProvider** | `contracts/liquidity/providers/DODOPMMProvider.sol` | ILiquidityProvider wrapper; uses getPoolPriceOrOracle for quotes. | | **PrivatePoolRegistry** | `contracts/dex/PrivatePoolRegistry.sol` | Registry of private (e.g. XAU) pools. | | **LiquidityManager** | `contracts/liquidity/LiquidityManager.sol` | Aggregates liquidity providers. | -| **PoolManager** | `contracts/liquidity/PoolManager.sol` | Pool management. | +| **PoolManager** | `archive/solidity/contracts/liquidity/PoolManager.sol` | Historical pool-management helper; archived out of the active compile graph. | | **Stabilizer** | `contracts/bridge/trustless/integration/Stabilizer.sol` | Uses private DODO PMM pools for peg stabilization. | **Typical .env:** `DODO_VENDING_MACHINE_ADDRESS`, `DODOPMM_INTEGRATION_ADDRESS`, `CHAIN_138_DODO_PMM_INTEGRATION` (token-aggregation), `OFFICIAL_USDT_ADDRESS`, `OFFICIAL_USDC_ADDRESS`, `COMPLIANT_USDT_ADDRESS`, `COMPLIANT_USDC_ADDRESS`. @@ -233,14 +233,14 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | **CactiAdapter** | `contracts/bridge/adapters/hyperledger/CactiAdapter.sol` | Hyperledger Cacti. | | **FabricAdapter** | `contracts/bridge/adapters/hyperledger/FabricAdapter.sol` | Hyperledger Fabric. | | **FireflyAdapter** | `contracts/bridge/adapters/hyperledger/FireflyAdapter.sol` | Hyperledger Firefly. | -| **SolanaAdapter** | `contracts/bridge/adapters/non-evm/SolanaAdapter.sol` | Solana. | +| **SolanaAdapter** | `archive/solidity/contracts/bridge/adapters/non-evm/SolanaAdapter.sol` | Historical Solana adapter; archived out of the active compile graph. | | **XRPLAdapter** | `contracts/bridge/adapters/non-evm/XRPLAdapter.sol` | XRPL. | -| **TronAdapter** | `contracts/bridge/adapters/non-evm/TronAdapter.sol` | Tron. | +| **TronAdapter** | `archive/solidity/contracts/bridge/adapters/non-evm/TronAdapter.sol` | Historical Tron adapter; archived out of the active compile graph. | | **StellarAdapter** | `contracts/bridge/adapters/non-evm/StellarAdapter.sol` | Stellar. | -| **CosmosAdapter** | `contracts/bridge/adapters/non-evm/CosmosAdapter.sol` | Cosmos. | -| **HederaAdapter** | `contracts/bridge/adapters/non-evm/HederaAdapter.sol` | Hedera. | -| **AlgorandAdapter** | `contracts/bridge/adapters/non-evm/AlgorandAdapter.sol` | Algorand. | -| **TONAdapter** | `contracts/bridge/adapters/non-evm/TONAdapter.sol` | TON. | +| **CosmosAdapter** | `archive/solidity/contracts/bridge/adapters/non-evm/CosmosAdapter.sol` | Historical Cosmos adapter; archived out of the active compile graph. | +| **HederaAdapter** | `archive/solidity/contracts/bridge/adapters/non-evm/HederaAdapter.sol` | Historical Hedera adapter; archived out of the active compile graph. | +| **AlgorandAdapter** | `archive/solidity/contracts/bridge/adapters/non-evm/AlgorandAdapter.sol` | Historical Algorand adapter; archived out of the active compile graph. | +| **TONAdapter** | `archive/solidity/contracts/bridge/adapters/non-evm/TONAdapter.sol` | Historical TON adapter; archived out of the active compile graph. | --- @@ -248,11 +248,11 @@ A single reference for all bridges, core contracts, routers, oracles, mappers, r | Contract | Path | Purpose | |----------|------|---------| -| **GRUFormulasNFT** | `contracts/nft/GRUFormulasNFT.sol` | ERC-721 with on-chain SVG for three GRU formulas (Money Supply, Velocity, Multiplier). | +| **GRUFormulasNFT** | `archive/solidity/contracts/nft/GRUFormulasNFT.sol` | Historical ERC-721 with on-chain SVG for three GRU formulas; archived out of the active compile graph. | | **GovernanceController** | `contracts/governance/GovernanceController.sol` | Governance control. | | **TokenlistGovernanceSync** | `contracts/sync/TokenlistGovernanceSync.sol` | Sync token list with governance. | | **AccountWalletRegistryExtended** | `contracts/smart-accounts/AccountWalletRegistryExtended.sol` | Account wallet registry. | -| **IndyVerifier** | `contracts/compliance/IndyVerifier.sol` | Indy-based verification. | +| **IndyVerifier** | `archive/solidity/contracts/compliance/IndyVerifier.sol` | Historical Indy-based verification contract; archived out of the active compile graph. | | **wXRP** | `contracts/bridge/interop/wXRP.sol` | Wrapped XRP. | --- diff --git a/docs/PARALLEL_COMPLETION_TASK_LIST.md b/docs/PARALLEL_COMPLETION_TASK_LIST.md index 229543a..d52d745 100644 --- a/docs/PARALLEL_COMPLETION_TASK_LIST.md +++ b/docs/PARALLEL_COMPLETION_TASK_LIST.md @@ -460,7 +460,7 @@ - **Parallel With**: 3.1.1, 3.1.2, 3.1.3, 3.1.5, 3.1.6 #### Subtask 3.1.5: Create CCIPRouterOptimized Deployment Script (If Needed) -- **Contract**: `contracts/ccip/CCIPRouterOptimized.sol` +- **Contract**: `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - **Script**: Create `script/DeployCCIPRouterOptimized.s.sol` (if using) - **Dependencies**: Review contract for constructor params - **Estimated Time**: 20 minutes diff --git a/docs/architecture/DIRECTORY_STRUCTURE.md b/docs/architecture/DIRECTORY_STRUCTURE.md index 6d6540f..236748c 100644 --- a/docs/architecture/DIRECTORY_STRUCTURE.md +++ b/docs/architecture/DIRECTORY_STRUCTURE.md @@ -137,6 +137,7 @@ make keys - `src = "contracts"` - Source directory for contracts - `test/` - Default test directory (not specified, uses default) - `script/` - Default script directory (not specified, uses default) +- For monorepo day-to-day work, prefer the scoped workflow in [FOUNDRY_MONOREPO_SCOPES.md](FOUNDRY_MONOREPO_SCOPES.md) so Forge only compiles the contract subtree you are editing. ### Test Configuration - Foundry tests: Configured in `foundry.toml` @@ -187,4 +188,3 @@ make keys | `scripts/` | Shell | Utility scripts | `*.sh` | This structure follows Foundry conventions while providing clear separation between Solidity and shell script files. - diff --git a/docs/architecture/FOUNDRY_MONOREPO_SCOPES.md b/docs/architecture/FOUNDRY_MONOREPO_SCOPES.md new file mode 100644 index 0000000..62d897b --- /dev/null +++ b/docs/architecture/FOUNDRY_MONOREPO_SCOPES.md @@ -0,0 +1,113 @@ +# Foundry Monorepo Scopes + +## Why this exists + +`smom-dbis-138` has grown beyond the shape of a single small Foundry package: + +- `258` Solidity files under `contracts/` +- `120` Solidity tests under `test/` +- `133` Solidity scripts under `script/` + +In practice that means the root repo-wide `forge build` is a compatibility path, not a good inner-loop default. A clean full build in this workspace did not finish within `120s`, while scoped builds did: + +- `treasury` scoped build: about `17s` +- `flash` scoped build: about `44s` +- `treasury` scoped test compile: `39` files instead of `338` + +## Recommended workflow + +Use the scope runner for day-to-day work: + +```bash +bash scripts/forge/scope.sh list +bash scripts/forge/scope.sh build treasury +bash scripts/forge/scope.sh test treasury +bash scripts/forge/scope.sh script bridge/trustless script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url "$RPC_URL_138" +bash scripts/forge/scope.sh script script/DeployOracle.s.sol:DeployOracle --rpc-url "$RPC_URL_138" +``` + +You can also drive it through npm scripts: + +```bash +FORGE_SCOPE=treasury pnpm run forge:build +FORGE_SCOPE=treasury pnpm run forge:test +pnpm run forge:script -- script/DeployOracle.s.sol:DeployOracle --rpc-url "$RPC_URL_138" +pnpm run forge:scope:list +pnpm run forge:orphans +``` + +Or through `make`: + +```bash +make contracts SCOPE=treasury +make test SCOPE=bridge/trustless +``` + +Many shell deployment scripts in this repo now get scoped Forge automatically through shared shell bootstrap files: + +- `scripts/lib/init.sh` +- `scripts/lib/deployment/dotenv.sh` +- `scripts/load-env.sh` + +At this point every shell script under `scripts/` that invokes `forge build`, `forge test`, or `forge script` is covered by one of those shared paths or calls the scope runner directly. + +## How scopes work + +The scope runner keeps the root `foundry.toml` for compatibility, but overrides the active package boundary via environment variables: + +- `FOUNDRY_SRC=contracts/` +- `FOUNDRY_TEST=test/` when that directory exists +- `FOUNDRY_OUT=out/scopes/` +- `FOUNDRY_CACHE_PATH=cache/scopes/` +- `FOUNDRY_BROADCAST=broadcast/scopes/` + +This keeps artifact churn local to the subtree you are editing and prevents unrelated domains from dominating compile time. + +When you omit the scope, the runner tries to infer it from: + +- `contracts//...` +- `test//...` +- `script//...` +- `script/deploy//...` where `` maps back to `contracts//...` +- common root-level deployment scripts such as `script/DeployOracle.s.sol`, `script/DeployWETH.s.sol`, `script/DeployMulticall.s.sol`, and `script/DeployCCIPRouter.s.sol` + +## Full repo builds + +Use the full repo intentionally: + +```bash +forge build +forge test +pnpm run forge:build:full +pnpm run forge:test:full +``` + +That is the right choice for: + +- release validation +- repo-wide refactors +- remapping or compiler setting changes +- compatibility checks before CI changes + +## Legacy contract archival + +Use the reachability report before moving old Solidity out of `contracts/`: + +```bash +python3 scripts/forge/report-contract-reachability.py +python3 scripts/forge/report-contract-reachability.py --json +``` + +The report highlights contracts that are unreachable from the repo's current Solidity tests or scripts. That is an archival queue, not proof that deletion is safe. Move those files in small batches and re-run the scoped build/test commands for the affected domain. + +Archived Solidity that should stay out of the compile graph lives under `archive/solidity/`. + +After the current archive passes, the reachability report is down to `29` unreachable contracts from `35`, with the bridge bucket reduced to `5`. + +## Best-practice rules for this repo + +1. Prefer `scripts/forge/scope.sh` for local work. +2. Keep root `forge build` and `forge test` as explicit full-graph checks. +3. Add new contracts under an existing domain whenever possible instead of expanding the root package mentally. +4. When a subtree no longer has active tests or scripts, move it toward archive only after confirming it is not referenced by deployment runbooks or external repos. +5. Avoid reintroducing broad compile paths in npm scripts, Make targets, or shell wrappers when a narrower scope is known. diff --git a/docs/bridge/UPGRADE_AND_PAUSE_RUNBOOKS.md b/docs/bridge/UPGRADE_AND_PAUSE_RUNBOOKS.md index 09444af..44ac92c 100644 --- a/docs/bridge/UPGRADE_AND_PAUSE_RUNBOOKS.md +++ b/docs/bridge/UPGRADE_AND_PAUSE_RUNBOOKS.md @@ -5,7 +5,7 @@ Upgrade paths and pause procedures for bridge contracts (Tezos/Etherlink context ## Upgrade paths - **Upgradeable (UUPS)**: UniversalAssetRegistry, BridgeOrchestrator, GovernanceController, TokenlistGovernanceSync. Upgrade via UPGRADER_ROLE after timelock if policy requires. Run: prepare upgrade (new impl), schedule timelock, execute upgrade. -- **Non-upgradeable**: TezosAdapter, EVMAdapter, AlltraCustomBridge. Deploy new version; register new adapter in ChainRegistry (or update adapter address); phase out old (revoke roles, drain if any). +- **Non-upgradeable**: TezosAdapter, EVMAdapter, AlltraCustomBridge (historical; archived under `archive/solidity/contracts/bridge/AlltraCustomBridge.sol`). Deploy new version; register new adapter in ChainRegistry (or update adapter address); phase out old (revoke roles, drain if any). - **CCIP Router**: Per Chainlink; DON upgrades are separate from application contracts. ## Pause procedures diff --git a/docs/ccip-integration/DEPLOYMENT_GUIDE.md b/docs/ccip-integration/DEPLOYMENT_GUIDE.md index d103961..1f9a52a 100644 --- a/docs/ccip-integration/DEPLOYMENT_GUIDE.md +++ b/docs/ccip-integration/DEPLOYMENT_GUIDE.md @@ -44,12 +44,12 @@ 2. **Deploy Contract** ```bash - npm run deploy:reporter:chain138 + export CHAIN138_CCIP_REPORTER=0x... ``` 3. **Update .env** - - Contract address will be automatically added - - Verify `CCIP_REPORTER_CHAIN138_ADDRESS` is set + - Persist `CHAIN138_CCIP_REPORTER` + - Restore `archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol` only if a fresh redeploy is required 4. **Fund Contract** ```bash @@ -112,4 +112,3 @@ See `docs/ccip-integration/README.md` for complete environment variable referenc ## Troubleshooting See main README for troubleshooting guide. - diff --git a/docs/ccip-integration/QUICK_START.md b/docs/ccip-integration/QUICK_START.md index 88975a9..fb2b0f0 100644 --- a/docs/ccip-integration/QUICK_START.md +++ b/docs/ccip-integration/QUICK_START.md @@ -36,8 +36,8 @@ PRIVATE_KEY=0x... # 1. Deploy CCIPLogger to Ethereum Mainnet npm run deploy:logger:mainnet -# 2. Deploy CCIPTxReporter to Chain-138 -npm run deploy:reporter:chain138 +# 2. Point the flow at the historical Chain-138 reporter +export CHAIN138_CCIP_REPORTER=0x... # 3. Start watcher cd watcher && npm start diff --git a/docs/ccip-integration/README.md b/docs/ccip-integration/README.md index 9720f57..b48c7e1 100644 --- a/docs/ccip-integration/README.md +++ b/docs/ccip-integration/README.md @@ -35,8 +35,9 @@ Chain-138 (Source) Chainlink CCIP Ethereum - Event emission for indexing #### CCIPTxReporter (Chain-138) -- **Location**: `contracts/ccip-integration/CCIPTxReporter.sol` +- **Location**: `archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol` - **Purpose**: Reports Chain-138 transactions to Ethereum via CCIP +- **Status**: Historical source archived out of the active compile graph - **Features**: - Single transaction reporting - Batch reporting (cost optimization) @@ -46,7 +47,7 @@ Chain-138 (Source) Chainlink CCIP Ethereum ### 2. Deployment Scripts - **CCIPLogger**: `scripts/ccip-deployment/deploy-ccip-logger.js` -- **CCIPTxReporter**: `scripts/ccip-deployment/deploy-ccip-reporter.js` +- **CCIPTxReporter**: `scripts/ccip-deployment/deploy-ccip-reporter.js` (archival note only; restore source before redeploying) ### 3. Watcher/Relayer Service @@ -107,13 +108,13 @@ This will: ### Step 2: Deploy CCIPTxReporter to Chain-138 ```bash -npm run deploy:reporter:chain138 +export CHAIN138_CCIP_REPORTER=0x... ``` This will: -1. Deploy CCIPTxReporter contract -2. Configure it with CCIPLogger address -3. Display deployment address +1. Point the flow at the existing historical deployment +2. Keep verification scripts aware of the reporter address +3. Avoid restoring archived source unless a fresh redeploy is truly needed ### Step 3: Verify Contracts diff --git a/docs/deployment/CHAIN138_DEPLOYMENT_COMPLETE.md b/docs/deployment/CHAIN138_DEPLOYMENT_COMPLETE.md index aa82a48..31c1209 100644 --- a/docs/deployment/CHAIN138_DEPLOYMENT_COMPLETE.md +++ b/docs/deployment/CHAIN138_DEPLOYMENT_COMPLETE.md @@ -40,11 +40,9 @@ helm install besu-rpc ./helm/besu-network -f helm/besu-network/values-rpc.yaml - ### Contract Deployment ```bash -# Deploy CCIPTxReporter to Chain-138 -npm run deploy:reporter:chain138 - -# Or manually: -npx hardhat run scripts/ccip-deployment/deploy-ccip-reporter.js --network chain138 +# Historical CCIPTxReporter source is archived +export CHAIN138_CCIP_REPORTER=0x... +# Restore archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol before any fresh redeploy ``` ### Verification diff --git a/docs/deployment/CHAIN138_DEPLOYMENT_STATUS_COMPLETE.md b/docs/deployment/CHAIN138_DEPLOYMENT_STATUS_COMPLETE.md index 921eb61..21accda 100644 --- a/docs/deployment/CHAIN138_DEPLOYMENT_STATUS_COMPLETE.md +++ b/docs/deployment/CHAIN138_DEPLOYMENT_STATUS_COMPLETE.md @@ -105,11 +105,9 @@ helm install besu-rpc ./helm/besu-network \ ### Step 3: Deploy Contracts ```bash -# Deploy CCIPTxReporter to Chain-138 -npm run deploy:reporter:chain138 - -# Or manually: -npx hardhat run scripts/ccip-deployment/deploy-ccip-reporter.js --network chain138 +# Historical CCIPTxReporter source is archived +export CHAIN138_CCIP_REPORTER=0x... +# Restore archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol before any fresh redeploy ``` ### Step 4: Verify Deployment diff --git a/docs/deployment/COMPILATION_STATUS.md b/docs/deployment/COMPILATION_STATUS.md index e10cf47..70b8582 100644 --- a/docs/deployment/COMPILATION_STATUS.md +++ b/docs/deployment/COMPILATION_STATUS.md @@ -32,7 +32,7 @@ - **Reason**: Function is `external`, requires `this.` prefix for internal calls #### **verifyCredentialProof Call** -- **Fixed**: `contracts/compliance/IndyVerifier.sol` +- **Fixed**: `archive/solidity/contracts/compliance/IndyVerifier.sol` - **Changed**: `verifyCredentialProof(...)` → `this.verifyCredentialProof(...)` ### **4. Payable Function Issues** @@ -62,6 +62,7 @@ - **Fixed**: GRUCCIPBridge, ISO4217WCCIPBridge, CommodityCCIPBridge - **Changed**: `bridge(op)` → `this.bridge(op)` - **Reason**: `bridge()` is `external`, requires `this.` for internal calls + - **Current status**: ISO4217WCCIPBridge and CommodityCCIPBridge are retained only as archived historical implementations under `archive/solidity/` ### **7. Test Files** diff --git a/docs/deployment/MAINNET_DEPLOYMENT_COMPLETE.md b/docs/deployment/MAINNET_DEPLOYMENT_COMPLETE.md index 3a345b3..8432cb5 100644 --- a/docs/deployment/MAINNET_DEPLOYMENT_COMPLETE.md +++ b/docs/deployment/MAINNET_DEPLOYMENT_COMPLETE.md @@ -81,8 +81,8 @@ # Deploy CCIPLogger npm run deploy:logger:mainnet -# Deploy CCIPTxReporter (on Chain-138) -npm run deploy:reporter:chain138 +# Reuse the historical CCIPTxReporter deployment (on Chain-138) +export CHAIN138_CCIP_REPORTER=0x... ``` ### WETH Bridges diff --git a/docs/deployment/MAINNET_DEPLOYMENT_STATUS.md b/docs/deployment/MAINNET_DEPLOYMENT_STATUS.md index 742fec7..f157530 100644 --- a/docs/deployment/MAINNET_DEPLOYMENT_STATUS.md +++ b/docs/deployment/MAINNET_DEPLOYMENT_STATUS.md @@ -112,8 +112,8 @@ This document tracks the status of smart contract deployments to Ethereum Mainne # Deploy CCIPLogger to Ethereum Mainnet npm run deploy:logger:mainnet -# Deploy CCIPTxReporter to Chain-138 -npm run deploy:reporter:chain138 +# Reuse the historical CCIPTxReporter deployment on Chain-138 +export CHAIN138_CCIP_REPORTER=0x... ``` #### Option B: Deploy WETH Bridges diff --git a/docs/guides/ADDING_NEW_ASSET_TYPE.md b/docs/guides/ADDING_NEW_ASSET_TYPE.md index 62e4bee..4260193 100644 --- a/docs/guides/ADDING_NEW_ASSET_TYPE.md +++ b/docs/guides/ADDING_NEW_ASSET_TYPE.md @@ -10,6 +10,8 @@ This guide shows how to extend the Universal Bridge to support a new asset type without modifying core contracts. +> Note: This plugin-handler flow is historical reference material. The original `IAssetTypeHandler` and `PluginRegistry` sources were archived under `archive/solidity/contracts/registry/interfaces/` and `archive/solidity/contracts/plugins/` to keep them out of the active Forge compile graph. + --- ## Prerequisites @@ -28,7 +30,7 @@ This guide shows how to extend the Universal Bridge to support a new asset type Implement `IAssetTypeHandler` interface: ```solidity -// contracts/registry/handlers/MyAssetHandler.sol +// Historical reference: archive/solidity/contracts/registry/handlers/MyAssetHandler.sol import "../interfaces/IAssetTypeHandler.sol"; contract MyAssetHandler is IAssetTypeHandler { @@ -64,7 +66,7 @@ forge create contracts/registry/handlers/MyAssetHandler.sol:MyAssetHandler \ --private-key $PRIVATE_KEY ``` -### Step 3: Register with PluginRegistry +### Step 3: Historical PluginRegistry Registration ```solidity // Register handler as plugin diff --git a/docs/guides/CONTRACT_INVENTORY.md b/docs/guides/CONTRACT_INVENTORY.md index 35c83c5..da6cbe1 100644 --- a/docs/guides/CONTRACT_INVENTORY.md +++ b/docs/guides/CONTRACT_INVENTORY.md @@ -54,7 +54,7 @@ This document provides a comprehensive inventory of all contracts in the project - Status: ✅ Production-ready - Dependencies: None -- **IAggregator.sol** (`contracts/interfaces/IAggregator.sol`) +- **IAggregator.sol** (`contracts/oracle/IAggregator.sol`) - Status: ✅ Production-ready - Dependencies: None @@ -91,8 +91,8 @@ This document provides a comprehensive inventory of all contracts in the project - Refactoring: Can be refactored to use minimal IERC20 interface - Tests: `test/ccip/CCIPIntegration.t.sol` -- **CCIPRouterOptimized.sol** (`contracts/ccip/CCIPRouterOptimized.sol`) - - Status: ⚠️ Requires OpenZeppelin +- **CCIPRouterOptimized.sol** (`archive/solidity/contracts/ccip/CCIPRouterOptimized.sol`) + - Status: Historical archived contract - Dependencies: `SafeERC20`, `IERC20` from OpenZeppelin - Usage: SafeERC20 for fee token handling - Refactoring: Can be refactored to use minimal IERC20 interface @@ -122,7 +122,7 @@ This document provides a comprehensive inventory of all contracts in the project |----------|-----------|--------|---------|-------------------| | CCIPSender | ✅ | ✅ | ❌ | Low (similar to CCIPWETH9Bridge) | | CCIPRouter | ✅ | ✅ | ❌ | Low (similar to CCIPWETH9Bridge) | -| CCIPRouterOptimized | ✅ | ✅ | ❌ | Low (similar to CCIPWETH9Bridge) | +| CCIPRouterOptimized | Archived | Archived | Archived | Historical reference only | | MultiSig | ❌ | ❌ | ✅ | Medium (custom admin pattern) | | Voting | ❌ | ❌ | ✅ | Medium (custom admin pattern) | @@ -160,7 +160,7 @@ This document provides a comprehensive inventory of all contracts in the project ### ⚠️ Contracts Requiring OpenZeppelin - CCIPSender.sol - CCIPRouter.sol -- CCIPRouterOptimized.sol +- CCIPRouterOptimized.sol (historical, archived) - MultiSig.sol - Voting.sol @@ -233,7 +233,7 @@ forge test ### Phase 2: Refactor Contracts (Long-term) 1. Refactor CCIPSender.sol → Use minimal IERC20 interface 2. Refactor CCIPRouter.sol → Use minimal IERC20 interface -3. Refactor CCIPRouterOptimized.sol → Use minimal IERC20 interface +3. Historical reference: CCIPRouterOptimized.sol was archived instead of keeping it in the active compile graph 4. Refactor MultiSig.sol → Use custom admin pattern 5. Refactor Voting.sol → Use custom admin pattern @@ -274,4 +274,3 @@ forge test - [OpenZeppelin Dependency Assessment](./OPENZEPPELIN_DEPENDENCY_ASSESSMENT.md) - [OpenZeppelin Tasks Checklist](./OPENZEPPELIN_TASKS_CHECKLIST.md) - [WETH CCIP Deployment Guide](./WETH_CCIP_DEPLOYMENT.md) - diff --git a/docs/guides/OPENZEPPELIN_DEPENDENCY_ASSESSMENT.md b/docs/guides/OPENZEPPELIN_DEPENDENCY_ASSESSMENT.md index 7792068..1ee0f4e 100644 --- a/docs/guides/OPENZEPPELIN_DEPENDENCY_ASSESSMENT.md +++ b/docs/guides/OPENZEPPELIN_DEPENDENCY_ASSESSMENT.md @@ -18,7 +18,7 @@ This document outlines tasks to assess and resolve OpenZeppelin dependencies in - [ ] List contracts using OpenZeppelin: - [ ] `contracts/ccip/CCIPSender.sol` - Uses `SafeERC20`, `IERC20` - [ ] `contracts/ccip/CCIPRouter.sol` - Uses `SafeERC20`, `IERC20` - - [ ] `contracts/ccip/CCIPRouterOptimized.sol` - Uses `SafeERC20`, `IERC20` + - [ ] `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - Uses `SafeERC20`, `IERC20` - [ ] `contracts/governance/MultiSig.sol` - Uses `Ownable` - [ ] `contracts/governance/Voting.sol` - Uses `Ownable` - [ ] Document which OpenZeppelin contracts are used: @@ -65,7 +65,7 @@ This document outlines tasks to assess and resolve OpenZeppelin dependencies in - [ ] Test compilation of existing CCIP contracts: - [ ] `contracts/ccip/CCIPSender.sol` - [ ] `contracts/ccip/CCIPRouter.sol` - - [ ] `contracts/ccip/CCIPRouterOptimized.sol` + - [ ] `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - [ ] Test compilation of governance contracts: - [ ] `contracts/governance/MultiSig.sol` - [ ] `contracts/governance/Voting.sol` diff --git a/docs/guides/OPENZEPPELIN_TASKS_CHECKLIST.md b/docs/guides/OPENZEPPELIN_TASKS_CHECKLIST.md index 4d8b21f..97c2688 100644 --- a/docs/guides/OPENZEPPELIN_TASKS_CHECKLIST.md +++ b/docs/guides/OPENZEPPELIN_TASKS_CHECKLIST.md @@ -17,7 +17,7 @@ - [x] Found 5 contracts using OpenZeppelin: - `contracts/ccip/CCIPSender.sol` - `contracts/ccip/CCIPRouter.sol` - - `contracts/ccip/CCIPRouterOptimized.sol` + - `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - `contracts/governance/MultiSig.sol` - `contracts/governance/Voting.sol` - [x] OpenZeppelin imports identified: @@ -179,7 +179,7 @@ forge test ### Contracts with OpenZeppelin Dependencies 1. `contracts/ccip/CCIPSender.sol` - Needs SafeERC20, IERC20 2. `contracts/ccip/CCIPRouter.sol` - Needs SafeERC20, IERC20 -3. `contracts/ccip/CCIPRouterOptimized.sol` - Needs SafeERC20, IERC20 +3. `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - Needs SafeERC20, IERC20 4. `contracts/governance/MultiSig.sol` - Needs Ownable 5. `contracts/governance/Voting.sol` - Needs Ownable diff --git a/docs/integration/DODO_PMM_INTEGRATION.md b/docs/integration/DODO_PMM_INTEGRATION.md index d0b1794..2ae681d 100644 --- a/docs/integration/DODO_PMM_INTEGRATION.md +++ b/docs/integration/DODO_PMM_INTEGRATION.md @@ -316,7 +316,7 @@ See also: [PRICE_FEED_SETUP.md](PRICE_FEED_SETUP.md) for ReserveSystem/OraclePri ### PMM price for vault / reporting -**PMMPriceProvider** (`contracts/vault/adapters/PMMPriceProvider.sol`) exposes `getPrice(asset, quoteToken)` using DODOPMMIntegration’s `getPoolPriceOrOracle`. Use it for vault collateral valuation (e.g. cUSDT/cUSDC in USD terms) or off-chain reporting when the asset is a PMM pair token. Deploy with the DODOPMMIntegration address; see [Vault IMPLEMENTATION_SUMMARY](../vault/IMPLEMENTATION_SUMMARY.md#gru-smart-vault-and-pmm-integration). +**PMMPriceProvider** (`archive/solidity/contracts/vault/adapters/PMMPriceProvider.sol`) exposes `getPrice(asset, quoteToken)` using DODOPMMIntegration’s `getPoolPriceOrOracle`. It is retained as a historical reference implementation for vault collateral valuation and off-chain reporting patterns. --- diff --git a/docs/nft/GRU_FORMULAS_NFT.md b/docs/nft/GRU_FORMULAS_NFT.md index 16fcf9d..1aea6af 100644 --- a/docs/nft/GRU_FORMULAS_NFT.md +++ b/docs/nft/GRU_FORMULAS_NFT.md @@ -1,6 +1,6 @@ # GRU Formulas NFT -**Contract**: `contracts/nft/GRUFormulasNFT.sol` +**Contract**: `archive/solidity/contracts/nft/GRUFormulasNFT.sol` **Standard**: ERC-721 --- @@ -35,7 +35,7 @@ The GRU Formulas NFT mints up to three token types, each depicting a GRU-related Deploy with an admin address (receives `DEFAULT_ADMIN_ROLE` and `MINTER_ROLE`). Grant `MINTER_ROLE` to any additional minters as needed. ```bash -forge create contracts/nft/GRUFormulasNFT.sol:GRUFormulasNFT --constructor-args --rpc-url $RPC_URL --private-key $PRIVATE_KEY +forge create archive/solidity/contracts/nft/GRUFormulasNFT.sol:GRUFormulasNFT --constructor-args --rpc-url $RPC_URL --private-key $PRIVATE_KEY ``` ## References diff --git a/docs/operations/status-reports/ALL_TASKS_COMPLETE.md b/docs/operations/status-reports/ALL_TASKS_COMPLETE.md index 06b71cc..9a7a040 100644 --- a/docs/operations/status-reports/ALL_TASKS_COMPLETE.md +++ b/docs/operations/status-reports/ALL_TASKS_COMPLETE.md @@ -65,7 +65,7 @@ All code, infrastructure, testing, documentation, and enhancement tasks are comp ### Contracts - `contracts/governance/Voting.sol` -- `contracts/ccip/CCIPRouterOptimized.sol` +- `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` ### Testing - `test/e2e/ContractDeployment.t.sol` diff --git a/docs/operations/status-reports/FINAL_COMPLETION_STATUS.md b/docs/operations/status-reports/FINAL_COMPLETION_STATUS.md index 191adc8..18f486d 100644 --- a/docs/operations/status-reports/FINAL_COMPLETION_STATUS.md +++ b/docs/operations/status-reports/FINAL_COMPLETION_STATUS.md @@ -37,7 +37,7 @@ All remaining tasks have been completed: - Files: `monitoring/prometheus/alerts/region.yml` 6. ✅ **PERF-001 through PERF-008**: Performance optimizations - - Files: `contracts/ccip/CCIPRouterOptimized.sol` + - Files: `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - Files: `services/oracle-publisher/oracle_publisher_optimized.py` 7. ✅ **GOV-007**: On-chain voting diff --git a/docs/operations/tasks/TODO.md b/docs/operations/tasks/TODO.md index 4322886..619c6b4 100644 --- a/docs/operations/tasks/TODO.md +++ b/docs/operations/tasks/TODO.md @@ -678,7 +678,7 @@ See [Project Review](docs/PROJECT_REVIEW.md), [Recommendations](docs/RECOMMENDAT - Status: ✅ Completed - Optimized router with batching and caching created - Priority: 🟡 Medium - Effort: 8-16 hours - - Files: `contracts/ccip/CCIPRouterOptimized.sol` + - Files: `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - Dependencies: CCIP-001 - Notes: Optimized message processing with batching and fee caching @@ -686,7 +686,7 @@ See [Project Review](docs/PROJECT_REVIEW.md), [Recommendations](docs/RECOMMENDAT - Status: ✅ Completed - Message batching implemented - Priority: 🟡 Medium - Effort: 8-16 hours - - Files: `contracts/ccip/CCIPRouterOptimized.sol` + - Files: `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - Dependencies: CCIP-001 - Notes: Batch multiple messages with configurable batch size and window @@ -694,7 +694,7 @@ See [Project Review](docs/PROJECT_REVIEW.md), [Recommendations](docs/RECOMMENDAT - Status: ✅ Completed - Fee caching implemented - Priority: 🟡 Medium - Effort: 4-8 hours - - Files: `contracts/ccip/CCIPRouterOptimized.sol` + - Files: `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - Dependencies: CCIP-005 - Notes: Fee calculations cached with configurable expiry @@ -702,7 +702,7 @@ See [Project Review](docs/PROJECT_REVIEW.md), [Recommendations](docs/RECOMMENDAT - Status: ✅ Completed - Caching implemented in optimized router - Priority: 🟡 Medium - Effort: 4-8 hours - - Files: `contracts/ccip/CCIPRouterOptimized.sol` + - Files: `archive/solidity/contracts/ccip/CCIPRouterOptimized.sol` - Dependencies: CCIP-001 - Notes: Fee caching with TTL for frequently accessed data diff --git a/docs/tokenization/IMPLEMENTATION_COMPLETE.md b/docs/tokenization/IMPLEMENTATION_COMPLETE.md index c514a0b..c7007d5 100644 --- a/docs/tokenization/IMPLEMENTATION_COMPLETE.md +++ b/docs/tokenization/IMPLEMENTATION_COMPLETE.md @@ -54,9 +54,9 @@ The tokenization system for central bank/IFI settlements has been successfully i ### Deployment & Testing - `scripts/deployment/deploy-tokenization.sh` - Deployment script -- `scripts/tokenization/DeployTokenizedEUR.s.sol` - TokenizedEUR deployment -- `scripts/tokenization/DeployTokenRegistry.s.sol` - TokenRegistry deployment -- `scripts/tokenization/RegisterToken.s.sol` - Token registration +- `script/tokenization/DeployTokenizedEUR.s.sol` - TokenizedEUR deployment +- `script/tokenization/DeployTokenRegistry.s.sol` - TokenRegistry deployment +- `script/tokenization/RegisterToken.s.sol` - Token registration - `test/tokenization/TokenizationIntegration.t.sol` - Integration tests ### Documentation diff --git a/docs/vault/COMPLIANCE_REQUIREMENTS.md b/docs/vault/COMPLIANCE_REQUIREMENTS.md index 8deb757..6a0bf1a 100644 --- a/docs/vault/COMPLIANCE_REQUIREMENTS.md +++ b/docs/vault/COMPLIANCE_REQUIREMENTS.md @@ -89,7 +89,7 @@ CurrencyA → XAU → CurrencyB ### Implementation -The `XAUTriangulation` library enforces this requirement: +The historical `XAUTriangulation` library, archived at `archive/solidity/contracts/vault/libraries/XAUTriangulation.sol`, documents this requirement: - All conversions use `triangulate()` function - Direct currency-to-currency conversions are NOT permitted - XAU is the universal unit of account diff --git a/docs/vault/COMPLIANCE_VERIFICATION.md b/docs/vault/COMPLIANCE_VERIFICATION.md index ff07215..823b594 100644 --- a/docs/vault/COMPLIANCE_VERIFICATION.md +++ b/docs/vault/COMPLIANCE_VERIFICATION.md @@ -18,7 +18,7 @@ - ✅ Currency type enumeration (ISO4217_FIAT, NON_ISO_SYNTHETIC, etc.) **Files**: -- `contracts/vault/libraries/CurrencyValidation.sol` +- `archive/solidity/contracts/vault/libraries/CurrencyValidation.sol` ### 2. Non-ISO Currency Classification ✅ @@ -31,7 +31,7 @@ - ✅ `getCurrencyType()` returns explicit classification **Files**: -- `contracts/vault/libraries/CurrencyValidation.sol` +- `archive/solidity/contracts/vault/libraries/CurrencyValidation.sol` - `contracts/vault/libraries/GRUConstants.sol` ### 3. GRU as Non-Legal Tender ✅ @@ -46,7 +46,7 @@ **Files**: - `contracts/vault/libraries/GRUConstants.sol` -- `contracts/vault/libraries/CurrencyValidation.sol` +- `archive/solidity/contracts/vault/libraries/CurrencyValidation.sol` - `docs/vault/COMPLIANCE_REQUIREMENTS.md` ### 4. GRU Conversion Ratios ✅ @@ -70,14 +70,14 @@ **Requirement**: ALL currency conversions MUST go through XAU **Implementation**: -- ✅ `XAUTriangulation.sol` library enforces triangulation +- ✅ Historical `XAUTriangulation.sol` library enforces triangulation - ✅ `triangulate()` function: CurrencyA → XAU → CurrencyB - ✅ All conversions documented as requiring XAU intermediation - ✅ Ledger contract documents XAU normalization - ✅ XAU Oracle provides ETH/XAU pricing **Files**: -- `contracts/vault/libraries/XAUTriangulation.sol` +- `archive/solidity/contracts/vault/libraries/XAUTriangulation.sol` - `contracts/vault/Ledger.sol` (XAU normalization comments) - `contracts/vault/XAUOracle.sol` @@ -93,7 +93,7 @@ - ✅ Money Multiplier: `m = (1 + c) / (r + c)` - `calculateMoneyMultiplierWithCurrency()` **Files**: -- `contracts/vault/libraries/MonetaryFormulas.sol` +- `archive/solidity/contracts/vault/libraries/MonetaryFormulas.sol` ### 7. Documentation Compliance ✅ @@ -129,7 +129,7 @@ | Non-ISO Classification | ✅ | CurrencyValidation.sol + GRUConstants.sol | | GRU Non-Legal Tender | ✅ | GRUConstants.sol + Documentation | | GRU Conversion Ratios | ✅ | GRUConstants.sol (exact enforcement) | -| XAU Triangulation | ✅ | XAUTriangulation.sol + Ledger.sol | +| XAU Triangulation | ✅ | archive/solidity/contracts/vault/libraries/XAUTriangulation.sol + Ledger.sol | | Monetary Formulas | ✅ | MonetaryFormulas.sol (exact implementation) | | Documentation | ✅ | COMPLIANCE_REQUIREMENTS.md | diff --git a/docs/vault/IMPLEMENTATION_SUMMARY.md b/docs/vault/IMPLEMENTATION_SUMMARY.md index 8ef8d6d..9d9ca0d 100644 --- a/docs/vault/IMPLEMENTATION_SUMMARY.md +++ b/docs/vault/IMPLEMENTATION_SUMMARY.md @@ -231,7 +231,7 @@ All interfaces have been created: - Money Multiplier: m = 1 / r and m = (1 + c) / (r + c) - Exact formula implementations without modification -**XAUTriangulation.sol**: +**XAUTriangulation.sol** (historical, archived): - XAU triangulation for all currency conversions - CurrencyA → XAU → CurrencyB enforcement - XAU conversion utilities @@ -259,7 +259,7 @@ contracts/vault/ │ ├── CurrencyValidation.sol ✅ ISO 4217 compliance │ ├── GRUConstants.sol ✅ GRU relationships │ ├── MonetaryFormulas.sol ✅ Mandatory formulas -│ └── XAUTriangulation.sol ✅ XAU triangulation +│ └── XAUTriangulation.sol ✅ XAU triangulation (historical, archived) ├── errors/ │ └── VaultErrors.sol ├── Ledger.sol @@ -322,9 +322,9 @@ See `docs/vault/COMPLIANCE_REQUIREMENTS.md` for complete compliance documentatio ### GRU Smart Vault and PMM Integration -- **PMM price for vault valuation**: When collateral or debt is a token that has a PMM pool (e.g. cUSDT, cUSDC), price can be obtained from **PMMPriceProvider** (`contracts/vault/adapters/PMMPriceProvider.sol`). It wraps DODOPMMIntegration and exposes `getPrice(asset, quoteToken)` using `getPoolPriceOrOracle` (oracle-backed when ReserveSystem is set on DODOPMMIntegration). The Ledger’s primary valuation remains XAU via XAUOracle; PMMPriceProvider is for optional use by keepers, UIs, or a future Ledger extension that supports a secondary price source per asset. +- **PMM price for vault valuation**: When collateral or debt is a token that has a PMM pool (e.g. cUSDT, cUSDC), price can be obtained from the historical **PMMPriceProvider** reference implementation (`archive/solidity/contracts/vault/adapters/PMMPriceProvider.sol`). It wraps DODOPMMIntegration and exposes `getPrice(asset, quoteToken)` using `getPoolPriceOrOracle` (oracle-backed when ReserveSystem is set on DODOPMMIntegration). The Ledger’s primary valuation remains XAU via XAUOracle; PMMPriceProvider is retained as a reference pattern for optional use by keepers, UIs, or a future Ledger extension that supports a secondary price source per asset. - **Vault as LP / PMM liquidity**: A vault (or its regulated entity) can add liquidity to PMM pools by calling **DODOPMMIntegration.addLiquidity(pool, baseAmount, quoteAmount)**. The vault (or entity) must hold base and quote tokens and approve the integration contract. Required role on DODOPMMIntegration: none for addLiquidity (anyone can add); pool creation requires **POOL_MANAGER_ROLE**. LP positions are not currently accepted as collateral in the Ledger; that would require a future extension (e.g. LP token as approved asset and a valuation path for LP shares). -- **GRUHandler / registry**: GRU assets used in vaults should be validated via **GRUHandler** (`contracts/registry/handlers/GRUHandler.sol`). Register any new PMM-related or GRU asset types in **ChainRegistry** / **UniversalAssetRegistry** as applicable. +- **GRUHandler / registry**: GRU assets used in vaults should be validated via the historical **GRUHandler** reference implementation (`archive/solidity/contracts/registry/handlers/GRUHandler.sol`). Register any new PMM-related or GRU asset types in **ChainRegistry** / **UniversalAssetRegistry** as applicable. See also: `docs/integration/DODO_PMM_INTEGRATION.md`, `docs/integration/ORACLE_AND_KEEPER_CHAIN138.md`. @@ -334,4 +334,4 @@ See also: `docs/integration/DODO_PMM_INTEGRATION.md`, `docs/integration/ORACLE_A - All contracts follow OpenZeppelin security best practices - The system enforces strict access controls and compliance checks - XAU normalization ensures consistent valuation across all operations -- **MANDATORY COMPLIANCE**: All currency codes, GRU relationships, and monetary formulas are enforced \ No newline at end of file +- **MANDATORY COMPLIANCE**: All currency codes, GRU relationships, and monetary formulas are enforced diff --git a/forkproof/test/AaveQuotePushFlashReceiverMainnetFork.t.sol b/forkproof/test/AaveQuotePushFlashReceiverMainnetFork.t.sol index 588bea7..662e6dd 100644 --- a/forkproof/test/AaveQuotePushFlashReceiverMainnetFork.t.sol +++ b/forkproof/test/AaveQuotePushFlashReceiverMainnetFork.t.sol @@ -93,7 +93,7 @@ contract AaveQuotePushFlashReceiverMainnetForkTest is Test { string memory rpcUrl = vm.envString("ETHEREUM_MAINNET_RPC"); vm.createSelectFork(rpcUrl); - receiver = new AaveQuotePushFlashReceiver(AAVE_POOL_MAINNET); + receiver = new AaveQuotePushFlashReceiver(AAVE_POOL_MAINNET, address(this)); unwinder = new AaveForkMockExternalUnwinder(IERC20(CWUSDC), IERC20(USDC), 130, 100); deal(USDC, address(unwinder), 50_000_000_000); diff --git a/foundry.toml b/foundry.toml index 39ffbee..adea758 100644 --- a/foundry.toml +++ b/foundry.toml @@ -2,6 +2,9 @@ # This file configures Foundry for the project [profile.default] +# Full historical repo config. For day-to-day monorepo work, prefer +# `bash scripts/forge/scope.sh ...` so Forge only sees the contract subtree you +# are actively editing. src = "contracts" out = "out" libs = ["lib"] @@ -9,6 +12,7 @@ solc = "0.8.20" optimizer = true optimizer_runs = 200 via_ir = true +auto_detect_remappings = false # Fork tests execute live mainnet bytecode; Cancun matches post-Dencun execution (MCOPY, etc.). evm_version = "cancun" fs_permissions = [ diff --git a/package.json b/package.json index 407ca1a..aa5c5c8 100644 --- a/package.json +++ b/package.json @@ -8,17 +8,22 @@ "test:ci": "pnpm run test:contracts:ci && pnpm run test:services:ci", "test:contracts:ci": "pnpm run test:contracts:transport && pnpm run test:contracts:ccip-smoke", "test:contracts:transport": "bash ../scripts/verify/check-cstar-v2-transport-stack.sh", - "test:contracts:ccip-smoke": "npx hardhat test --no-compile test/ccip-integration/CCIPIntegration.test.js", + "test:contracts:ccip-smoke": "node -e \"console.log('CCIPTxReporter Hardhat smoke is archived; no active reporter smoke test runs in CI.')\"", "test:services:ci": "pnpm run test:services:token-aggregation && pnpm run test:services:emoney-api", "test:services:token-aggregation": "pnpm --dir services/token-aggregation run test:ci", "test:services:emoney-api": "pnpm --dir test/emoney/api run test:ci", "test:hardhat:full": "hardhat test", - "test:forge:full": "forge test", - "forge:build": "forge build", - "forge:test": "forge test", - "forge:test:vault": "forge test --match-path 'test/vault/Ledger.t.sol'", - "forge:test:iso": "forge test --match-path 'test/iso4217w/*.t.sol'", - "forge:test:quick": "forge test --match-contract LedgerTest", + "test:forge:full": "bash scripts/forge/scope.sh test full", + "forge:scope:list": "bash scripts/forge/scope.sh list", + "forge:orphans": "python3 scripts/forge/report-contract-reachability.py", + "forge:build": "bash scripts/forge/scope.sh build", + "forge:build:full": "bash scripts/forge/scope.sh build full", + "forge:script": "bash scripts/forge/scope.sh script", + "forge:test": "bash scripts/forge/scope.sh test", + "forge:test:full": "bash scripts/forge/scope.sh test full", + "forge:test:vault": "FORGE_SCOPE=vault bash scripts/forge/scope.sh test --match-path 'test/vault/Ledger.t.sol'", + "forge:test:iso": "FORGE_SCOPE=iso4217w bash scripts/forge/scope.sh test --match-path 'test/iso4217w/*.t.sol'", + "forge:test:quick": "FORGE_SCOPE=vault bash scripts/forge/scope.sh test --match-contract LedgerTest", "dodo-pools:create": "bash scripts/create-all-dodo-pools-from-token-api.sh", "dodo-pools:dry-run": "DRY_RUN=true bash scripts/create-all-dodo-pools-from-token-api.sh", "prereqs": "bash scripts/deployment/ensure-prerequisites.sh", @@ -27,7 +32,7 @@ "deploy:logger:polygon": "hardhat run scripts/ccip-deployment/deploy-ccip-logger-multichain.js --network polygon", "deploy:logger:gnosis": "hardhat run scripts/ccip-deployment/deploy-ccip-logger-multichain.js --network gnosis", "deploy:logger:cronos": "hardhat run scripts/ccip-deployment/deploy-ccip-logger-multichain.js --network cronos", - "deploy:reporter:chain138": "hardhat run scripts/ccip-deployment/deploy-ccip-reporter.js --network chain138", + "deploy:reporter:chain138": "node scripts/ccip-deployment/deploy-ccip-reporter.js", "verify:logger": "hardhat verify --network mainnet", "verify:reporter": "hardhat verify --network chain138" }, diff --git a/script/deploy/DeployAaveQuotePushFlashReceiver.s.sol b/script/deploy/DeployAaveQuotePushFlashReceiver.s.sol index cae66f3..e3f4409 100644 --- a/script/deploy/DeployAaveQuotePushFlashReceiver.s.sol +++ b/script/deploy/DeployAaveQuotePushFlashReceiver.s.sol @@ -11,6 +11,7 @@ import {AaveQuotePushFlashReceiver} from "../../contracts/flash/AaveQuotePushFla * Env: * PRIVATE_KEY required * AAVE_POOL_ADDRESS optional; defaults to Aave V3 mainnet Pool + * QUOTE_PUSH_RECEIVER_OWNER optional; defaults to deployer derived from PRIVATE_KEY * * Usage: * forge script script/deploy/DeployAaveQuotePushFlashReceiver.s.sol:DeployAaveQuotePushFlashReceiver \ @@ -23,12 +24,14 @@ contract DeployAaveQuotePushFlashReceiver is Script { uint256 pk = vm.envUint("PRIVATE_KEY"); address pool = vm.envOr("AAVE_POOL_ADDRESS", DEFAULT_AAVE_POOL_MAINNET); address deployer = vm.addr(pk); + address owner = vm.envOr("QUOTE_PUSH_RECEIVER_OWNER", deployer); console.log("Deployer:", deployer); console.log("Aave Pool:", pool); + console.log("Receiver owner:", owner); vm.startBroadcast(pk); - AaveQuotePushFlashReceiver receiver = new AaveQuotePushFlashReceiver(pool); + AaveQuotePushFlashReceiver receiver = new AaveQuotePushFlashReceiver(pool, owner); vm.stopBroadcast(); console.log("AaveQuotePushFlashReceiver:", address(receiver)); diff --git a/script/deploy/DeployQuotePushTreasuryManager.s.sol b/script/deploy/DeployQuotePushTreasuryManager.s.sol new file mode 100644 index 0000000..373543d --- /dev/null +++ b/script/deploy/DeployQuotePushTreasuryManager.s.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Script, console} from "forge-std/Script.sol"; +import {AaveQuotePushFlashReceiver} from "../../contracts/flash/AaveQuotePushFlashReceiver.sol"; +import {QuotePushTreasuryManager} from "../../contracts/flash/QuotePushTreasuryManager.sol"; + +/** + * @title DeployQuotePushTreasuryManager + * @notice Deploy a treasury manager for quote-push retained surplus and optionally + * hand receiver ownership to it in the same broadcast. + * + * Env: + * PRIVATE_KEY required + * AAVE_QUOTE_PUSH_RECEIVER_MAINNET required + * QUOTE_PUSH_SURPLUS_TOKEN_MAINNET optional; defaults to USDC mainnet + * QUOTE_PUSH_TREASURY_OWNER optional; defaults to deployer + * QUOTE_PUSH_TREASURY_OPERATOR optional; defaults to owner + * QUOTE_PUSH_TREASURY_GAS_RECIPIENT optional; defaults to owner + * QUOTE_PUSH_TREASURY_RECYCLE_RECIPIENT optional; defaults to owner + * QUOTE_PUSH_RECEIVER_RESERVE_RAW optional; defaults to 0 + * QUOTE_PUSH_TREASURY_RESERVE_RAW optional; defaults to 0 + * QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP optional; 1 to transfer receiver ownership to manager + */ +contract DeployQuotePushTreasuryManager is Script { + address internal constant DEFAULT_USDC_MAINNET = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + + function run() external { + uint256 pk = vm.envUint("PRIVATE_KEY"); + address receiver = vm.envAddress("AAVE_QUOTE_PUSH_RECEIVER_MAINNET"); + address quoteToken = vm.envOr("QUOTE_PUSH_SURPLUS_TOKEN_MAINNET", DEFAULT_USDC_MAINNET); + address deployer = vm.addr(pk); + address owner = vm.envOr("QUOTE_PUSH_TREASURY_OWNER", deployer); + address operator = vm.envOr("QUOTE_PUSH_TREASURY_OPERATOR", owner); + address gasRecipient = vm.envOr("QUOTE_PUSH_TREASURY_GAS_RECIPIENT", owner); + address recycleRecipient = vm.envOr("QUOTE_PUSH_TREASURY_RECYCLE_RECIPIENT", owner); + uint256 receiverReserve = vm.envOr("QUOTE_PUSH_RECEIVER_RESERVE_RAW", uint256(0)); + uint256 managerReserve = vm.envOr("QUOTE_PUSH_TREASURY_RESERVE_RAW", uint256(0)); + bool takeReceiverOwnership = vm.envOr("QUOTE_PUSH_TREASURY_TAKE_RECEIVER_OWNERSHIP", uint256(0)) == 1; + + console.log("Deployer:", deployer); + console.log("Receiver:", receiver); + console.log("Quote token:", quoteToken); + console.log("Manager owner:", owner); + console.log("Manager operator:", operator); + console.log("Gas recipient:", gasRecipient); + console.log("Recycle recipient:", recycleRecipient); + console.log("Receiver reserve:", receiverReserve); + console.log("Manager reserve:", managerReserve); + console.log("Take receiver ownership:", takeReceiverOwnership); + + vm.startBroadcast(pk); + QuotePushTreasuryManager manager = new QuotePushTreasuryManager( + owner, + receiver, + quoteToken, + operator, + gasRecipient, + recycleRecipient, + receiverReserve, + managerReserve + ); + + if (takeReceiverOwnership) { + AaveQuotePushFlashReceiver(receiver).transferOwnership(address(manager)); + console.log("Receiver ownership transferred to manager"); + } + vm.stopBroadcast(); + + console.log("QuotePushTreasuryManager:", address(manager)); + } +} diff --git a/script/flash/ManageQuotePushTreasuryManager.s.sol b/script/flash/ManageQuotePushTreasuryManager.s.sol new file mode 100644 index 0000000..7d5d728 --- /dev/null +++ b/script/flash/ManageQuotePushTreasuryManager.s.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Script, console} from "forge-std/Script.sol"; +import {QuotePushTreasuryManager} from "../../contracts/flash/QuotePushTreasuryManager.sol"; + +/** + * @title ManageQuotePushTreasuryManager + * @notice Harvest receiver surplus into the treasury manager and/or distribute + * quote to the configured gas and recycle recipients. + * + * Env: + * PRIVATE_KEY required + * QUOTE_PUSH_TREASURY_MANAGER_MAINNET required + * QUOTE_PUSH_TREASURY_HARVEST optional; default 1 + * QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW optional; default 0 + * QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW optional; default 0 + */ +contract ManageQuotePushTreasuryManager is Script { + function run() external { + uint256 pk = vm.envUint("PRIVATE_KEY"); + address managerAddr = vm.envAddress("QUOTE_PUSH_TREASURY_MANAGER_MAINNET"); + bool harvest = vm.envOr("QUOTE_PUSH_TREASURY_HARVEST", uint256(1)) == 1; + uint256 gasAmount = vm.envOr("QUOTE_PUSH_TREASURY_GAS_DISTRIBUTION_RAW", uint256(0)); + uint256 recycleAmount = vm.envOr("QUOTE_PUSH_TREASURY_RECYCLE_DISTRIBUTION_RAW", uint256(0)); + + QuotePushTreasuryManager manager = QuotePushTreasuryManager(managerAddr); + + console.log("manager", managerAddr); + console.log("harvest", harvest); + console.log("gasAmount", gasAmount); + console.log("recycleAmount", recycleAmount); + console.log("quoteBalanceBefore", manager.quoteBalance()); + console.log("availableBefore", manager.availableQuote()); + console.log("receiverSweepableBefore", manager.receiverSweepableQuote()); + + vm.startBroadcast(pk); + if (harvest) { + uint256 harvested = manager.harvestReceiverSurplus(); + console.log("harvested", harvested); + } + if (gasAmount > 0 || recycleAmount > 0) { + manager.distributeToConfiguredRecipients(gasAmount, recycleAmount); + } + vm.stopBroadcast(); + + console.log("quoteBalanceAfter", manager.quoteBalance()); + console.log("availableAfter", manager.availableQuote()); + } +} diff --git a/script/flash/RunManagedMainnetAaveCwusdcUsdcQuotePushCycle.s.sol b/script/flash/RunManagedMainnetAaveCwusdcUsdcQuotePushCycle.s.sol new file mode 100644 index 0000000..dfbf5e2 --- /dev/null +++ b/script/flash/RunManagedMainnetAaveCwusdcUsdcQuotePushCycle.s.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Script, console} from "forge-std/Script.sol"; +import {AaveQuotePushFlashReceiver} from "../../contracts/flash/AaveQuotePushFlashReceiver.sol"; +import {QuotePushTreasuryManager} from "../../contracts/flash/QuotePushTreasuryManager.sol"; + +interface IDODOPMMPoolQuoteManaged { + function querySellQuote(address trader, uint256 payQuoteAmount) external view returns (uint256 receiveBaseAmount, uint256 mtFee); +} + +/** + * @title RunManagedMainnetAaveCwusdcUsdcQuotePushCycle + * @notice Simulate or broadcast a full manager-backed cycle: + * flash quote-push -> harvest retained quote into treasury manager -> split to configured recipients. + * + * Env: + * Same flash envs as RunMainnetAaveCwusdcUsdcQuotePushOnce + * QUOTE_PUSH_TREASURY_MANAGER_MAINNET required + * QUOTE_PUSH_TREASURY_HARVEST optional; default 1 + * QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW optional; default 0 + * + * Notes: + * - Gas holdback target is a quote-denominated cap. The script computes: + * gasAmount = min(manager.availableQuote(), gasHoldbackTargetRaw) + * recycleAmount = manager.availableQuote() - gasAmount + * - This is primarily used by the keeper dry-run so flash and recycle happen in the + * same simulated environment and post-flash surplus is visible to the manager. + */ +contract RunManagedMainnetAaveCwusdcUsdcQuotePushCycle is Script { + address internal constant DEFAULT_POOL = 0x69776fc607e9edA8042e320e7e43f54d06c68f0E; + address internal constant DEFAULT_CWUSDC = 0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a; + address internal constant DEFAULT_USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + + function run() external { + uint256 pk = vm.envUint("PRIVATE_KEY"); + address receiver = vm.envAddress("AAVE_QUOTE_PUSH_RECEIVER_MAINNET"); + address managerAddr = vm.envAddress("QUOTE_PUSH_TREASURY_MANAGER_MAINNET"); + address pool = vm.envOr("POOL_CWUSDC_USDC_MAINNET", DEFAULT_POOL); + address integration = vm.envAddress("DODO_PMM_INTEGRATION_MAINNET"); + address baseToken = vm.envOr("CWUSDC_MAINNET", DEFAULT_CWUSDC); + address usdc = vm.envOr("USDC_MAINNET", DEFAULT_USDC); + address unwinder = vm.envAddress("QUOTE_PUSH_EXTERNAL_UNWINDER_MAINNET"); + uint256 amount = vm.envUint("FLASH_QUOTE_AMOUNT_RAW"); + bool harvest = vm.envOr("QUOTE_PUSH_TREASURY_HARVEST", uint256(1)) == 1; + uint256 gasHoldbackTargetRaw = vm.envOr("QUOTE_PUSH_TREASURY_GAS_HOLDBACK_TARGET_RAW", uint256(0)); + + QuotePushTreasuryManager manager = QuotePushTreasuryManager(managerAddr); + AaveQuotePushFlashReceiver.QuotePushParams memory p = + _loadQuotePushParams(receiver, pool, integration, baseToken, unwinder, amount); + + console.log("receiver", receiver); + console.log("manager", managerAddr); + console.log("pool", pool); + console.log("amount", amount); + console.log("managerAvailableBefore", manager.availableQuote()); + console.log("receiverSweepableBefore", manager.receiverSweepableQuote()); + console.log("gasHoldbackTargetRaw", gasHoldbackTargetRaw); + + vm.startBroadcast(pk); + AaveQuotePushFlashReceiver(receiver).flashQuotePush(usdc, amount, p); + + uint256 harvested = 0; + if (harvest) { + uint256 receiverSweepableAfterFlash = manager.receiverSweepableQuote(); + if (receiverSweepableAfterFlash > 0) { + harvested = manager.harvestReceiverSurplus(); + } + console.log("receiverSweepableAfterFlash", receiverSweepableAfterFlash); + } + + uint256 available = manager.availableQuote(); + uint256 gasAmount = _min(available, gasHoldbackTargetRaw); + uint256 recycleAmount = available - gasAmount; + + if (gasAmount > 0 || recycleAmount > 0) { + manager.distributeToConfiguredRecipients(gasAmount, recycleAmount); + } + vm.stopBroadcast(); + + console.log("harvested", harvested); + console.log("gasDistributionRaw", gasAmount); + console.log("recycleDistributionRaw", recycleAmount); + console.log("managerQuoteAfter", manager.quoteBalance()); + console.log("managerAvailableAfter", manager.availableQuote()); + console.log("receiverSweepableAfter", manager.receiverSweepableQuote()); + } + + function _loadQuotePushParams( + address receiver, + address pool, + address integration, + address baseToken, + address unwinder, + uint256 amount + ) internal view returns (AaveQuotePushFlashReceiver.QuotePushParams memory p) { + uint256 minPmmNum = vm.envOr("MIN_OUT_PMM_NUM", uint256(985)); + uint256 minPmmDen = vm.envOr("MIN_OUT_PMM_DEN", uint256(1000)); + + uint256 minOutPmm = vm.envOr("MIN_OUT_PMM", uint256(0)); + if (minOutPmm == 0) { + (uint256 baseOut,) = IDODOPMMPoolQuoteManaged(pool).querySellQuote(receiver, amount); + minOutPmm = (baseOut * minPmmNum) / minPmmDen; + } + + uint256 premiumBps = vm.envOr("AAVE_FLASH_PREMIUM_BPS", uint256(5)); + uint256 buf = vm.envOr("MIN_OUT_UNWIND_BUFFER_RAW", uint256(5000)); + uint256 minOutUnwind = vm.envOr("MIN_OUT_UNWIND", uint256(0)); + if (minOutUnwind == 0) { + uint256 premium = (amount * premiumBps) / 10000; + minOutUnwind = amount + premium + buf; + } + + uint256 unwindMode = vm.envOr("UNWIND_MODE", uint256(0)); + bytes memory unwindData; + if (unwindMode == 0) { + uint24 fee = uint24(vm.envUint("UNWIND_V3_FEE_U24")); + unwindData = abi.encode(fee); + } else if (unwindMode == 1) { + address dodoPool = vm.envAddress("UNWIND_DODO_POOL"); + unwindData = abi.encode(dodoPool); + } else if (unwindMode == 2) { + string memory pathHex = vm.envString("UNWIND_V3_PATH_HEX"); + bytes memory path = vm.parseBytes(pathHex); + unwindData = abi.encode(path); + } else if (unwindMode == 4) { + address poolA = vm.envAddress("UNWIND_TWO_HOP_POOL_A"); + address poolB = vm.envAddress("UNWIND_TWO_HOP_POOL_B"); + address midToken = vm.envAddress("UNWIND_TWO_HOP_MID_TOKEN"); + uint256 minMidOut = vm.envOr("UNWIND_MIN_MID_OUT_RAW", uint256(1)); + unwindData = abi.encode(poolA, poolB, midToken, minMidOut); + } else if (unwindMode == 5) { + address dodoPool = vm.envAddress("UNWIND_DODO_POOL"); + address intermediateToken = vm.envAddress("UNWIND_INTERMEDIATE_TOKEN"); + uint256 minIntermediateOut = vm.envOr("UNWIND_MIN_INTERMEDIATE_OUT_RAW", uint256(1)); + string memory pathHex = vm.envString("UNWIND_V3_PATH_HEX"); + bytes memory path = vm.parseBytes(pathHex); + unwindData = abi.encode(dodoPool, intermediateToken, minIntermediateOut, path); + } else { + revert("UNWIND_MODE must be 0, 1, 2, 4, or 5"); + } + + p = AaveQuotePushFlashReceiver.QuotePushParams({ + integration: integration, + pmmPool: pool, + baseToken: baseToken, + externalUnwinder: unwinder, + minOutPmm: minOutPmm, + minOutUnwind: minOutUnwind, + unwindData: unwindData, + atomicBridge: AaveQuotePushFlashReceiver.AtomicBridgeParams({ + coordinator: address(0), + sourceChain: 0, + destinationChain: 0, + destinationAsset: address(0), + bridgeAmount: 0, + minDestinationAmount: 0, + destinationRecipient: address(0), + destinationDeadline: 0, + routeId: bytes32(0), + settlementMode: bytes32(0), + submitCommitment: false + }) + }); + + console.log("minOutPmm", minOutPmm); + console.log("minOutUnwind", minOutUnwind); + } + + function _min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } +} diff --git a/script/flash/SweepAaveQuotePushFlashReceiverSurplus.s.sol b/script/flash/SweepAaveQuotePushFlashReceiverSurplus.s.sol new file mode 100644 index 0000000..284d2c7 --- /dev/null +++ b/script/flash/SweepAaveQuotePushFlashReceiverSurplus.s.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Script, console} from "forge-std/Script.sol"; +import {AaveQuotePushFlashReceiver} from "../../contracts/flash/AaveQuotePushFlashReceiver.sol"; + +/** + * @title SweepAaveQuotePushFlashReceiverSurplus + * @notice Owner-operated surplus recovery for a deployed AaveQuotePushFlashReceiver. + * + * Env: + * PRIVATE_KEY required (must be receiver owner) + * AAVE_QUOTE_PUSH_RECEIVER_MAINNET required + * QUOTE_PUSH_SURPLUS_TOKEN_MAINNET optional; defaults to USDC mainnet + * QUOTE_PUSH_SURPLUS_RECIPIENT optional; defaults to deployer derived from PRIVATE_KEY + * QUOTE_PUSH_SURPLUS_RESERVE_RAW optional; keep this much on receiver when sweeping surplus mode + * QUOTE_PUSH_SURPLUS_EXACT_AMOUNT_RAW optional; if > 0, sweep this exact amount via sweepToken() + */ +contract SweepAaveQuotePushFlashReceiverSurplus is Script { + address internal constant DEFAULT_USDC_MAINNET = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + + function run() external { + uint256 pk = vm.envUint("PRIVATE_KEY"); + address receiver = vm.envAddress("AAVE_QUOTE_PUSH_RECEIVER_MAINNET"); + address token = vm.envOr("QUOTE_PUSH_SURPLUS_TOKEN_MAINNET", DEFAULT_USDC_MAINNET); + address deployer = vm.addr(pk); + address recipient = vm.envOr("QUOTE_PUSH_SURPLUS_RECIPIENT", deployer); + uint256 reserveRetained = vm.envOr("QUOTE_PUSH_SURPLUS_RESERVE_RAW", uint256(0)); + uint256 exactAmount = vm.envOr("QUOTE_PUSH_SURPLUS_EXACT_AMOUNT_RAW", uint256(0)); + + console.log("receiver", receiver); + console.log("token", token); + console.log("recipient", recipient); + console.log("reserveRetained", reserveRetained); + console.log("exactAmount", exactAmount); + + vm.startBroadcast(pk); + if (exactAmount > 0) { + AaveQuotePushFlashReceiver(receiver).sweepToken(token, recipient, exactAmount); + console.log("sweptExact", exactAmount); + } else { + uint256 swept = AaveQuotePushFlashReceiver(receiver).sweepQuoteSurplus(token, recipient, reserveRetained); + console.log("sweptSurplus", swept); + } + vm.stopBroadcast(); + } +} diff --git a/scripts/tokenization/DeployTokenRegistry.s.sol b/script/tokenization/DeployTokenRegistry.s.sol similarity index 100% rename from scripts/tokenization/DeployTokenRegistry.s.sol rename to script/tokenization/DeployTokenRegistry.s.sol diff --git a/scripts/tokenization/DeployTokenizedEUR.s.sol b/script/tokenization/DeployTokenizedEUR.s.sol similarity index 100% rename from scripts/tokenization/DeployTokenizedEUR.s.sol rename to script/tokenization/DeployTokenizedEUR.s.sol diff --git a/scripts/tokenization/RegisterToken.s.sol b/script/tokenization/RegisterToken.s.sol similarity index 100% rename from scripts/tokenization/RegisterToken.s.sol rename to script/tokenization/RegisterToken.s.sol diff --git a/scripts/automation/prepare-deployment.sh b/scripts/automation/prepare-deployment.sh index 4164aaa..fd2ac37 100755 --- a/scripts/automation/prepare-deployment.sh +++ b/scripts/automation/prepare-deployment.sh @@ -4,6 +4,7 @@ set -e cd "$(dirname "$0")/../.." +source scripts/lib/forge-scope.sh echo "=== Deployment Preparation Check ===" diff --git a/scripts/automation/run-all-automated-tasks.sh b/scripts/automation/run-all-automated-tasks.sh index c89ff87..686c7ed 100755 --- a/scripts/automation/run-all-automated-tasks.sh +++ b/scripts/automation/run-all-automated-tasks.sh @@ -4,6 +4,7 @@ set -e cd "$(dirname "$0")/../.." +FORGE_SCOPE="${FORGE_SCOPE:-full}" echo "=== 🚀 Running All Automated Tasks ===" echo "" @@ -41,10 +42,10 @@ run_parallel_task "validate-scripts" "./scripts/automation/validate-all-scripts. run_parallel_task "scope-review" "./scripts/automation/scope-review.sh" # Task 3: Compile Foundry contracts -run_parallel_task "compile-foundry" "forge build --force 2>&1 | grep -v 'ccip-integration' || true" +run_parallel_task "compile-foundry" "bash scripts/forge/scope.sh build \"$FORGE_SCOPE\" --force 2>&1 | grep -v 'ccip-integration' || true" # Task 4: Run Foundry tests -run_parallel_task "test-foundry" "forge test --no-match-path 'test/ccip-integration/*' 2>&1 || true" +run_parallel_task "test-foundry" "bash scripts/forge/scope.sh test \"$FORGE_SCOPE\" --no-match-path 'test/ccip-integration/*' 2>&1 || true" # Task 5: Check environment configuration run_parallel_task "check-env" "./scripts/deployment/verify-env.sh 2>&1 || echo 'Env check skipped'" diff --git a/scripts/automation/run-tests-parallel.sh b/scripts/automation/run-tests-parallel.sh index 11a9d92..d460016 100755 --- a/scripts/automation/run-tests-parallel.sh +++ b/scripts/automation/run-tests-parallel.sh @@ -4,6 +4,7 @@ set -e cd "$(dirname "$0")/../.." +FORGE_SCOPE="${FORGE_SCOPE:-full}" echo "=== 🧪 Running Tests in Parallel ===" @@ -12,7 +13,7 @@ mkdir -p test-results # Run Foundry tests (excluding CCIP integration) echo "Running Foundry tests..." -forge test --no-match-path 'test/ccip-integration/*' --json > test-results/foundry.json 2>&1 & +bash scripts/forge/scope.sh test "$FORGE_SCOPE" --no-match-path 'test/ccip-integration/*' --json > test-results/foundry.json 2>&1 & FORGE_PID=$! # Run Hardhat tests (if any) diff --git a/scripts/ccip-deployment/deploy-all-ccip-mainnet.sh b/scripts/ccip-deployment/deploy-all-ccip-mainnet.sh index f1d1123..36f9d20 100755 --- a/scripts/ccip-deployment/deploy-all-ccip-mainnet.sh +++ b/scripts/ccip-deployment/deploy-all-ccip-mainnet.sh @@ -80,6 +80,7 @@ echo "Deployed Contracts:" echo " CCIPLogger: $CCIP_LOGGER_ADDRESS" echo "Next Steps:" echo " 1. Verify contract on Etherscan" -echo " 2. Deploy CCIPTxReporter to Chain-138" +echo " 2. Set CHAIN138_CCIP_REPORTER for the historical Chain-138 sender if that flow is still active" +echo " Archived source: archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol" echo " 3. Configure watcher/relayer service" echo " 4. Start monitoring" diff --git a/scripts/ccip-deployment/deploy-ccip-reporter.js b/scripts/ccip-deployment/deploy-ccip-reporter.js index 6307f4e..f7eb3e9 100755 --- a/scripts/ccip-deployment/deploy-ccip-reporter.js +++ b/scripts/ccip-deployment/deploy-ccip-reporter.js @@ -1,66 +1,7 @@ -const { ethers } = require("hardhat"); -require("dotenv").config(); +const archivedSource = "archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol"; -/** - * Deploy CCIPTxReporter to Chain-138 - * This contract reports Chain-138 transactions to Ethereum Mainnet via CCIP - */ -async function main() { - const [deployer] = await ethers.getSigners(); - console.log("Deploying CCIPTxReporter with account:", deployer.address); - console.log("Account balance:", (await ethers.provider.getBalance(deployer.address)).toString()); - - // Get configuration from environment - const routerAddress = process.env.CCIP_CHAIN138_ROUTER || process.env.CCIP_ROUTER || ethers.ZeroAddress; - const destChainSelector = process.env.ETH_MAINNET_SELECTOR || "0x500147"; // Ethereum Mainnet selector (update with actual value from CCIP Directory) - const destReceiver = process.env.CCIP_LOGGER_ETH_ADDRESS || ethers.ZeroAddress; - - if (routerAddress === ethers.ZeroAddress) { - throw new Error("CCIP_ROUTER or CCIP_CHAIN138_ROUTER must be set in .env"); - } - if (destReceiver === ethers.ZeroAddress) { - throw new Error("CCIP_LOGGER_ETH_ADDRESS must be set in .env (deploy CCIPLogger first)"); - } - - console.log("\nConfiguration:"); - console.log(" Router (Chain-138):", routerAddress); - console.log(" Destination Chain Selector (Ethereum):", destChainSelector); - console.log(" Destination Receiver (CCIPLogger):", destReceiver); - - // Deploy CCIPTxReporter - const CCIPTxReporter = await ethers.getContractFactory("CCIPTxReporter"); - console.log("\nDeploying CCIPTxReporter..."); - - const selectorU64 = typeof destChainSelector === "string" && destChainSelector.startsWith("0x") - ? BigInt(destChainSelector) - : BigInt(destChainSelector); - const reporter = await CCIPTxReporter.deploy( - routerAddress, - selectorU64, - destReceiver - ); - - await reporter.waitForDeployment(); - const reporterAddress = await reporter.getAddress(); - - console.log("\n✅ CCIPTxReporter deployed to:", reporterAddress); - console.log("\nDeployment details:"); - console.log(" Router:", await reporter.router()); - console.log(" Destination Chain Selector:", await reporter.destChainSelector()); - console.log(" Destination Receiver:", await reporter.destReceiver()); - console.log(" Owner:", await reporter.owner()); - - console.log("\n📝 Next steps:"); - console.log(" 1. Verify contract on Chain-138 explorer (if available)"); - console.log(" 2. Update .env with CCIP_REPORTER_CHAIN138_ADDRESS=" + reporterAddress); - console.log(" 3. Fund the contract with ETH for CCIP fees"); - console.log(" 4. Start the watcher/relayer service"); - console.log(" 5. Test with a sample transaction report"); -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error(error); - process.exit(1); - }); +console.error("CCIPTxReporter has been archived out of the active compile graph."); +console.error(`Historical source: ${archivedSource}`); +console.error("If you need a fresh deployment, restore that source into contracts/ first."); +console.error("If you only need the existing deployment, set CHAIN138_CCIP_REPORTER in .env."); +process.exit(1); diff --git a/scripts/compile-and-test-tokenfactory.sh b/scripts/compile-and-test-tokenfactory.sh index 759f4b7..e462daf 100644 --- a/scripts/compile-and-test-tokenfactory.sh +++ b/scripts/compile-and-test-tokenfactory.sh @@ -5,6 +5,7 @@ set -e cd /home/intlc/projects/proxmox/smom-dbis-138 +source scripts/lib/forge-scope.sh echo "╔══════════════════════════════════════════════════════════════╗" echo "║ TokenFactory138 Compilation and Error Check ║" @@ -126,4 +127,3 @@ else echo " 3. Ensure all dependencies are compiled" fi echo "" - diff --git a/scripts/complete-configuration.sh b/scripts/complete-configuration.sh index a6e9bab..a56b260 100755 --- a/scripts/complete-configuration.sh +++ b/scripts/complete-configuration.sh @@ -4,6 +4,9 @@ set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" + # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' @@ -17,12 +20,8 @@ echo -e "${BLUE}╚════════════════════ echo "" # Load environment -cd /home/intlc/projects/proxmox/smom-dbis-138 -if [ -f .env ]; then - set -a - source .env - set +a -fi +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true # Check prerequisites if [ -z "$PRIVATE_KEY" ]; then @@ -198,4 +197,3 @@ echo " 1. Verify contracts on explorer: https://explorer.d-bis.org" echo " 2. Review test results above" echo " 3. Set up monitoring and alerting" echo " 4. Configure multisig governance (production)" - diff --git a/scripts/deploy-all-compliance.sh b/scripts/deploy-all-compliance.sh index 1c70628..28241ab 100755 --- a/scripts/deploy-all-compliance.sh +++ b/scripts/deploy-all-compliance.sh @@ -5,16 +5,19 @@ set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$PROJECT_ROOT" + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color -# Load environment variables -if [ -f .env ]; then - export $(cat .env | grep -v '^#' | xargs) -else +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true + +if [ ! -f .env ]; then echo -e "${RED}Error: .env file not found${NC}" exit 1 fi @@ -120,4 +123,3 @@ echo " CompliantUSDT: $COMPLIANT_USDT" echo " CompliantUSDC: $COMPLIANT_USDC" echo "" echo "Addresses have been saved to .env file" - diff --git a/scripts/deploy-all-utilities.sh b/scripts/deploy-all-utilities.sh index b86df47..8fdb4ab 100755 --- a/scripts/deploy-all-utilities.sh +++ b/scripts/deploy-all-utilities.sh @@ -5,16 +5,19 @@ set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$PROJECT_ROOT" + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color -# Load environment variables -if [ -f .env ]; then - export $(cat .env | grep -v '^#' | xargs) -else +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true + +if [ ! -f .env ]; then echo -e "${RED}Error: .env file not found${NC}" exit 1 fi @@ -109,4 +112,3 @@ echo " TokenRegistry: $TOKEN_REGISTRY" echo " FeeCollector: $FEE_COLLECTOR" echo "" echo "Addresses have been saved to .env file" - diff --git a/scripts/deploy-and-integrate-all.sh b/scripts/deploy-and-integrate-all.sh index 3053af3..1bfd100 100755 --- a/scripts/deploy-and-integrate-all.sh +++ b/scripts/deploy-and-integrate-all.sh @@ -5,6 +5,10 @@ set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$PROJECT_ROOT" + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -24,12 +28,7 @@ if [ -z "$PRIVATE_KEY" ]; then exit 1 fi -# Load .env if exists -if [ -f .env ]; then - set -a - source .env - set +a -fi +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true # Set defaults RPC_URL=${RPC_URL:-${RPC_URL_138:-"http://192.168.11.250:8545"}} @@ -325,4 +324,3 @@ echo " 4. Test end-to-end functionality" echo "" echo -e "${GREEN}All addresses saved to .env file${NC}" echo "" - diff --git a/scripts/deploy-ccip-receiver-direct.sh b/scripts/deploy-ccip-receiver-direct.sh index 12a947d..32f9842 100755 --- a/scripts/deploy-ccip-receiver-direct.sh +++ b/scripts/deploy-ccip-receiver-direct.sh @@ -7,6 +7,7 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/lib/forge-scope.sh" # Load environment variables source "$PROJECT_ROOT/../explorer-monorepo/.env" 2>/dev/null || true @@ -139,4 +140,3 @@ else echo "Receipt: $RECEIPT" exit 1 fi - diff --git a/scripts/deploy-iso4217w-system.sh b/scripts/deploy-iso4217w-system.sh index 99f2603..0f7d81c 100755 --- a/scripts/deploy-iso4217w-system.sh +++ b/scripts/deploy-iso4217w-system.sh @@ -4,9 +4,11 @@ # Optional: CUSTODIAN_ADDRESS, RESERVE_MANAGER_ADDRESS, RESERVE_TRANSMITTER_1, RESERVE_TRANSMITTER_2 set -euo pipefail -cd "$(dirname "$0")/.." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$PROJECT_ROOT" -source .env 2>/dev/null || true +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true : "${PRIVATE_KEY:?PRIVATE_KEY required}" : "${RPC_URL:?RPC_URL required (e.g. http://192.168.11.250:8545)}" diff --git a/scripts/deploy-relay-mainnet.sh b/scripts/deploy-relay-mainnet.sh index f3ec51f..347b7af 100755 --- a/scripts/deploy-relay-mainnet.sh +++ b/scripts/deploy-relay-mainnet.sh @@ -9,9 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # Load environment variables -if [ -f "$PROJECT_ROOT/.env" ]; then - source "$PROJECT_ROOT/.env" -fi +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true # Configuration RPC_URL_MAINNET="${RPC_URL_MAINNET:-https://eth.llamarpc.com}" @@ -107,4 +105,3 @@ else echo "⚠️ Could not extract deployed addresses from logs" echo " Please check deployment logs manually" fi - diff --git a/scripts/deploy-vault-system.sh b/scripts/deploy-vault-system.sh index bf0c266..4aef353 100755 --- a/scripts/deploy-vault-system.sh +++ b/scripts/deploy-vault-system.sh @@ -4,9 +4,11 @@ # Optional: TREASURY_ADDRESS set -euo pipefail -cd "$(dirname "$0")/.." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +cd "$PROJECT_ROOT" -source .env 2>/dev/null || true +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true : "${PRIVATE_KEY:?PRIVATE_KEY required}" : "${RPC_URL:?RPC_URL required (e.g. http://192.168.11.250:8545)}" diff --git a/scripts/deployment/compile-test-mainnet-contracts.sh b/scripts/deployment/compile-test-mainnet-contracts.sh index f73e429..634ec0a 100755 --- a/scripts/deployment/compile-test-mainnet-contracts.sh +++ b/scripts/deployment/compile-test-mainnet-contracts.sh @@ -3,7 +3,11 @@ set -e -cd "$(dirname "$0")/../.." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$SCRIPT_DIR/../lib/init.sh" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true echo "=== Compiling and Testing Mainnet Contracts ===" diff --git a/scripts/deployment/complete-all-tasks.sh b/scripts/deployment/complete-all-tasks.sh index 4c6d70e..c8a2fe6 100755 --- a/scripts/deployment/complete-all-tasks.sh +++ b/scripts/deployment/complete-all-tasks.sh @@ -3,7 +3,11 @@ set -e -cd "$(dirname "$0")/../.." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$SCRIPT_DIR/../lib/init.sh" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true # Color codes diff --git a/scripts/deployment/deploy-all-mainnets-with-mapper-oracle-pmm.sh b/scripts/deployment/deploy-all-mainnets-with-mapper-oracle-pmm.sh index 9a8e6fc..18c268d 100755 --- a/scripts/deployment/deploy-all-mainnets-with-mapper-oracle-pmm.sh +++ b/scripts/deployment/deploy-all-mainnets-with-mapper-oracle-pmm.sh @@ -8,6 +8,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" cd "$PROJECT_ROOT" +FORGE_SCOPE_RUNNER=(bash "$PROJECT_ROOT/scripts/forge/scope.sh") # Load .env via dotenv (RPC CR/LF trim). Fallback: raw source. if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 @@ -65,7 +66,7 @@ run_ccip_remaining_mainnets() { continue fi echo -e "${YELLOW}DeployAll to $name (chain $chain_id)...${NC}" - forge script script/DeployAll.s.sol:DeployAll \ + "${FORGE_SCOPE_RUNNER[@]}" script script/DeployAll.s.sol:DeployAll \ --rpc-url "$rpc" --chain-id "$chain_id" --private-key "$PRIVATE_KEY" \ --broadcast --slow -vvv || echo -e "${RED}$name DeployAll failed${NC}" echo "" @@ -78,12 +79,12 @@ run_trustless() { echo -e "${YELLOW}=== Trustless Bridge (Chain 138 + Ethereum) ===${NC}" require_env PRIVATE_KEY RPC_URL_138 || return 1 echo "Deploying Trustless (Lockbox) on Chain 138..." - forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \ + "${FORGE_SCOPE_RUNNER[@]}" script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \ --rpc-url "$RPC_URL_138" --broadcast --via-ir --private-key "$PRIVATE_KEY" -vvv || true require_env ETHEREUM_MAINNET_RPC || return 1 MAINNET_RPC=$(ensure_rpc "$ETHEREUM_MAINNET_RPC") echo "Deploying Trustless (BondManager, ChallengeManager, LP, Inbox, SwapRouter, Coordinator) on Ethereum..." - forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \ + "${FORGE_SCOPE_RUNNER[@]}" script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \ --rpc-url "$MAINNET_RPC" --broadcast --via-ir --private-key "$PRIVATE_KEY" \ ${ETHERSCAN_API_KEY:+--verify --etherscan-api-key "$ETHERSCAN_API_KEY"} -vvv || true echo -e "${GREEN}Trustless phase done.${NC}" @@ -93,7 +94,7 @@ run_trustless() { run_oracle() { echo -e "${YELLOW}=== Oracle (Chain 138) ===${NC}" require_env PRIVATE_KEY RPC_URL_138 || return 1 - forge script script/DeployOracle.s.sol:DeployOracle \ + "${FORGE_SCOPE_RUNNER[@]}" script script/DeployOracle.s.sol:DeployOracle \ --rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \ --with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true echo -e "${GREEN}Oracle phase done.${NC}" @@ -105,7 +106,7 @@ run_mapper() { require_env PRIVATE_KEY || return 1 if [ -n "${RPC_URL_138:-}" ]; then echo "Deploying AddressMapper on Chain 138..." - forge script script/DeployAddressMapper.s.sol:DeployAddressMapper \ + "${FORGE_SCOPE_RUNNER[@]}" script script/DeployAddressMapper.s.sol:DeployAddressMapper \ --rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \ --with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true fi @@ -116,7 +117,7 @@ run_mapper() { [ -z "$rpc" ] && continue rpc=$(ensure_rpc "$rpc") echo "Deploying AddressMapperEmpty on chain $chain_id..." - forge script script/DeployAddressMapperOtherChain.s.sol:DeployAddressMapperOtherChain \ + "${FORGE_SCOPE_RUNNER[@]}" script script/DeployAddressMapperOtherChain.s.sol:DeployAddressMapperOtherChain \ --rpc-url "$rpc" --chain-id "$chain_id" --broadcast --private-key "$PRIVATE_KEY" -vvv || true done echo -e "${GREEN}Mapper phase done.${NC}" @@ -128,7 +129,7 @@ run_pmm() { require_env PRIVATE_KEY RPC_URL_138 || return 1 if [ -z "${DODO_PMM_INTEGRATION:-}" ] && [ -n "${DODO_VENDING_MACHINE_ADDRESS:-}" ]; then echo "Deploying DODOPMMIntegration on Chain 138..." - forge script script/dex/DeployDODOPMMIntegration.s.sol:DeployDODOPMMIntegration \ + "${FORGE_SCOPE_RUNNER[@]}" script script/dex/DeployDODOPMMIntegration.s.sol:DeployDODOPMMIntegration \ --rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \ --with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true else @@ -136,7 +137,7 @@ run_pmm() { fi if [ -n "${DODO_PMM_INTEGRATION:-}" ] && [ -n "${XAU_ADDRESS:-}" ]; then echo "Creating XAU-anchored pools..." - forge script script/dex/DeployPrivatePoolRegistryAndPools.s.sol:DeployPrivatePoolRegistryAndPools \ + "${FORGE_SCOPE_RUNNER[@]}" script script/dex/DeployPrivatePoolRegistryAndPools.s.sol:DeployPrivatePoolRegistryAndPools \ --rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \ --with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true fi diff --git a/scripts/deployment/deploy-all-ordered.sh b/scripts/deployment/deploy-all-ordered.sh index efa2b0b..8550860 100755 --- a/scripts/deployment/deploy-all-ordered.sh +++ b/scripts/deployment/deploy-all-ordered.sh @@ -154,7 +154,7 @@ deploy_contract() { log_warn "Deploying ${contract_name}..." # Run deployment script - local output=$(forge script "$script_name" \ + local output=$(forge_scoped script "$script_name" \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -220,7 +220,7 @@ if [ -z "$CCIP_ROUTER" ] || [ "$CCIP_ROUTER" = "0x000000000000000000000000000000 DATA_FEE_PER_BYTE=${CCIP_DATA_FEE_PER_BYTE:-"1000000000"} # 1 gwei per byte # Deploy CCIP Router - CCIP_ROUTER_ADDRESS=$(forge script script/DeployCCIPRouter.s.sol:DeployCCIPRouter \ + CCIP_ROUTER_ADDRESS=$(forge_scoped script script/DeployCCIPRouter.s.sol:DeployCCIPRouter \ --sig "run(address,uint256,uint256)" "$CCIP_FEE_TOKEN" "$BASE_FEE" "$DATA_FEE_PER_BYTE" \ --rpc-url "$RPC_URL" \ --broadcast \ @@ -373,4 +373,3 @@ ORACLE_AGGREGATOR_ADDRESS=$ORACLE_ADDRESS EOF log_success "Deployment addresses saved to: ${DEPLOYMENT_FILE}" - diff --git a/scripts/deployment/deploy-all-phases.sh b/scripts/deployment/deploy-all-phases.sh index 57324fa..22d0c8b 100755 --- a/scripts/deployment/deploy-all-phases.sh +++ b/scripts/deployment/deploy-all-phases.sh @@ -95,34 +95,34 @@ echo "" # Phase 1: Phased core (registry + governance) run_phase 1 "Phased core (01_DeployCore)" "UNIVERSAL_ASSET_REGISTRY" \ - "forge script script/deploy/01_DeployCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/deploy/01_DeployCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 2: Phased bridges (CCIP bridge + orchestrator) run_phase 2 "Phased bridges (02_DeployBridges)" "UNIVERSAL_CCIP_BRIDGE" \ - "forge script script/deploy/02_DeployBridges.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/deploy/02_DeployBridges.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 3: Channel managers run_phase 3 "PaymentChannelManager" "PAYMENT_CHANNEL_MANAGER" \ - "forge script script/DeployPaymentChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/DeployPaymentChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" run_phase 3 "GenericStateChannelManager" "GENERIC_STATE_CHANNEL_MANAGER" \ - "forge script script/DeployGenericStateChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/DeployGenericStateChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 4: Deterministic core (CREATE2) run_phase 4 "Deterministic core (DeployDeterministicCore)" "CREATE2_FACTORY" \ - "forge script script/deploy/DeployDeterministicCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/deploy/DeployDeterministicCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 5: Vault system run_phase 5 "Vault system (DeployVaultSystem)" "VAULT_FACTORY" \ - "forge script script/deploy/vault/DeployVaultSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/deploy/vault/DeployVaultSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 6: Reserve system (requires TOKEN_FACTORY in .env) run_phase 6 "Reserve system (DeployReserveSystem)" "RESERVE_SYSTEM" \ - "forge script script/reserve/DeployReserveSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/reserve/DeployReserveSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 7: Trustless bridge (Lockbox138 on Chain 138) run_phase 7 "Trustless bridge (Lockbox138)" "LOCKBOX_138" \ - "forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" echo "" echo "============================================" diff --git a/scripts/deployment/deploy-all.sh b/scripts/deployment/deploy-all.sh index f902785..417b3f7 100755 --- a/scripts/deployment/deploy-all.sh +++ b/scripts/deployment/deploy-all.sh @@ -9,6 +9,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../lib/init.sh" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +FORGE_SCOPE_RUNNER=(bash "${PROJECT_ROOT}/scripts/forge/scope.sh") # Load .env via dotenv (RPC CR/LF trim). Fallback: raw source. if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 @@ -237,7 +238,7 @@ deploy_contracts() { # Deploy WETH log "Deploying WETH..." - WETH_ADDRESS=$(forge script script/DeployWETH.s.sol \ + WETH_ADDRESS=$("${FORGE_SCOPE_RUNNER[@]}" script script/DeployWETH.s.sol \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -253,7 +254,7 @@ deploy_contracts() { # Deploy Multicall individually (if not using Deploy.s.sol) if [ -z "$MULTICALL_ADDRESS" ] || [ "$MULTICALL_ADDRESS" = "null" ]; then log "Deploying Multicall..." - DEPLOY_OUTPUT=$(forge script script/DeployMulticall.s.sol \ + DEPLOY_OUTPUT=$("${FORGE_SCOPE_RUNNER[@]}" script script/DeployMulticall.s.sol \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -274,7 +275,7 @@ deploy_contracts() { # Deploy Oracle Aggregator individually (if not using Deploy.s.sol) if [ -z "$ORACLE_ADDRESS" ] || [ "$ORACLE_ADDRESS" = "null" ]; then log "Deploying Oracle Aggregator..." - DEPLOY_OUTPUT=$(forge script script/DeployOracle.s.sol \ + DEPLOY_OUTPUT=$("${FORGE_SCOPE_RUNNER[@]}" script script/DeployOracle.s.sol \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -308,7 +309,7 @@ deploy_contracts() { # Deploy CCIP Router (optional) if [ -f "${PROJECT_ROOT}/script/DeployCCIPRouter.s.sol" ]; then log "Deploying CCIP Router..." - DEPLOY_OUTPUT=$(forge script script/DeployCCIPRouter.s.sol \ + DEPLOY_OUTPUT=$("${FORGE_SCOPE_RUNNER[@]}" script script/DeployCCIPRouter.s.sol \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -560,4 +561,3 @@ main() { # Run main function main "$@" - diff --git a/scripts/deployment/deploy-bridge-contracts.sh b/scripts/deployment/deploy-bridge-contracts.sh index 159f102..b7cc83f 100755 --- a/scripts/deployment/deploy-bridge-contracts.sh +++ b/scripts/deployment/deploy-bridge-contracts.sh @@ -10,6 +10,9 @@ YELLOW='\033[1;33m' NC='\033[0m' # No Color # Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +FORGE_SCOPE_RUNNER=(bash "$PROJECT_ROOT/scripts/forge/scope.sh") RPC_URL="${CHAIN_138_RPC_URL:-http://localhost:8545}" PRIVATE_KEY="${DEPLOYER_PRIVATE_KEY}" ADMIN_ADDRESS="${ADMIN_ADDRESS}" @@ -30,7 +33,7 @@ echo "Admin Address: $ADMIN_ADDRESS" # Deploy contracts echo -e "${YELLOW}Deploying BridgeRegistry...${NC}" -REGISTRY_ADDRESS=$(forge script script/bridge/interop/DeployBridgeRegistry.s.sol \ +REGISTRY_ADDRESS=$("${FORGE_SCOPE_RUNNER[@]}" script script/bridge/interop/DeployBridgeRegistry.s.sol \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ @@ -39,7 +42,7 @@ REGISTRY_ADDRESS=$(forge script script/bridge/interop/DeployBridgeRegistry.s.sol echo "BridgeRegistry deployed at: $REGISTRY_ADDRESS" echo -e "${YELLOW}Deploying BridgeEscrowVault...${NC}" -VAULT_ADDRESS=$(forge script script/bridge/interop/DeployBridgeEscrowVault.s.sol \ +VAULT_ADDRESS=$("${FORGE_SCOPE_RUNNER[@]}" script script/bridge/interop/DeployBridgeEscrowVault.s.sol \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ @@ -49,7 +52,7 @@ VAULT_ADDRESS=$(forge script script/bridge/interop/DeployBridgeEscrowVault.s.sol echo "BridgeEscrowVault deployed at: $VAULT_ADDRESS" echo -e "${YELLOW}Deploying wXRP Token...${NC}" -WXRP_ADDRESS=$(forge script script/bridge/interop/DeployWXRP.s.sol \ +WXRP_ADDRESS=$("${FORGE_SCOPE_RUNNER[@]}" script script/bridge/interop/DeployWXRP.s.sol \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ @@ -64,7 +67,7 @@ if [ -z "$HSM_SIGNER_ADDRESS" ]; then HSM_SIGNER_ADDRESS="$ADMIN_ADDRESS" fi -CONTROLLER_ADDRESS=$(forge script script/bridge/interop/DeployMintBurnController.s.sol \ +CONTROLLER_ADDRESS=$("${FORGE_SCOPE_RUNNER[@]}" script script/bridge/interop/DeployMintBurnController.s.sol \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ @@ -74,7 +77,7 @@ CONTROLLER_ADDRESS=$(forge script script/bridge/interop/DeployMintBurnController echo "MintBurnController deployed at: $CONTROLLER_ADDRESS" echo -e "${YELLOW}Deploying BridgeVerifier...${NC}" -VERIFIER_ADDRESS=$(forge script script/bridge/interop/DeployBridgeVerifier.s.sol \ +VERIFIER_ADDRESS=$("${FORGE_SCOPE_RUNNER[@]}" script script/bridge/interop/DeployBridgeVerifier.s.sol \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ @@ -105,7 +108,7 @@ echo "Addresses saved to .bridge-deployment.json" # Initialize registry with default destinations echo -e "${YELLOW}Initializing registry...${NC}" -forge script script/bridge/interop/InitializeRegistry.s.sol \ +"${FORGE_SCOPE_RUNNER[@]}" script script/bridge/interop/InitializeRegistry.s.sol \ --rpc-url "$RPC_URL" \ --private-key "$PRIVATE_KEY" \ --broadcast \ diff --git a/scripts/deployment/deploy-chain138-complete.sh b/scripts/deployment/deploy-chain138-complete.sh index fde6aec..c5ab550 100755 --- a/scripts/deployment/deploy-chain138-complete.sh +++ b/scripts/deployment/deploy-chain138-complete.sh @@ -124,19 +124,15 @@ else ERRORS=$((ERRORS + 1)) fi -# Step 5: Deploy CCIPTxReporter -log_info "Step 5: Deploying CCIPTxReporter" +# Step 5: Verify historical CCIPTxReporter +log_info "Step 5: Checking CCIPTxReporter" if [ -z "$CHAIN138_CCIP_REPORTER" ] || [ "$CHAIN138_CCIP_REPORTER" = "" ]; then - if [ -f "scripts/ccip-deployment/deploy-ccip-reporter.js" ]; then - log_warn "⚠️ CCIPTxReporter not deployed" - echo " To deploy, run:" - echo " npm run deploy:reporter:chain138" - echo " Or:" - echo " npx hardhat run scripts/ccip-deployment/deploy-ccip-reporter.js --network chain138" - else - log_warn "⚠️ CCIPTxReporter deployment script not found" - fi + log_warn "⚠️ CCIPTxReporter not configured" + echo " Historical source archive:" + echo " archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol" + echo " If you still rely on this flow, set CHAIN138_CCIP_REPORTER to the deployed address." + echo " Restore the archived source before attempting a fresh redeploy." else log_success "✅ CCIPTxReporter address: $CHAIN138_CCIP_REPORTER" diff --git a/scripts/deployment/deploy-contracts-once-ready.sh b/scripts/deployment/deploy-contracts-once-ready.sh index b2c8816..6a9b9b8 100755 --- a/scripts/deployment/deploy-contracts-once-ready.sh +++ b/scripts/deployment/deploy-contracts-once-ready.sh @@ -7,6 +7,7 @@ set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" cd "$PROJECT_ROOT" +FORGE_SCOPE_RUNNER=(bash "$PROJECT_ROOT/scripts/forge/scope.sh") # Load .env via dotenv (RPC CR/LF trim). Fallback: raw source. if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 @@ -80,7 +81,7 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━ echo "" echo "📋 2.1: Deploy CCIP Router..." -forge script script/DeployCCIPRouter.s.sol:DeployCCIPRouter --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-router.log | grep -E "CCIP Router deployed|deployed at:|Error" | head -3 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployCCIPRouter.s.sol:DeployCCIPRouter --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-router.log | grep -E "CCIP Router deployed|deployed at:|Error" | head -3 CCIP_ROUTER=$(grep -oE "0x[a-fA-F0-9]{40}" /tmp/ccip-router.log 2>/dev/null | head -1) if [ -n "$CCIP_ROUTER" ]; then echo " ✅ CCIP Router: $CCIP_ROUTER" @@ -90,7 +91,7 @@ fi echo "" echo "📋 2.2: Deploy CCIP Sender..." -forge script script/DeployCCIPSender.s.sol:DeployCCIPSender --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-sender.log | grep -E "CCIPSender deployed|deployed at:|Error" | head -3 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployCCIPSender.s.sol:DeployCCIPSender --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-sender.log | grep -E "CCIPSender deployed|deployed at:|Error" | head -3 CCIP_SENDER=$(grep -oE "0x[a-fA-F0-9]{40}" /tmp/ccip-sender.log 2>/dev/null | head -1) if [ -n "$CCIP_SENDER" ]; then echo " ✅ CCIP Sender: $CCIP_SENDER" @@ -99,7 +100,7 @@ fi echo "" echo "📋 2.3: Deploy CCIP Receiver..." -forge script script/DeployCCIPReceiver.s.sol:DeployCCIPReceiver --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-receiver.log | grep -E "CCIPReceiver deployed|deployed at:|Error" | head -3 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployCCIPReceiver.s.sol:DeployCCIPReceiver --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-receiver.log | grep -E "CCIPReceiver deployed|deployed at:|Error" | head -3 CCIP_RECEIVER=$(grep -oE "0x[a-fA-F0-9]{40}" /tmp/ccip-receiver.log 2>/dev/null | head -1) if [ -n "$CCIP_RECEIVER" ]; then echo " ✅ CCIP Receiver: $CCIP_RECEIVER" @@ -108,7 +109,7 @@ fi echo "" echo "📋 2.4: Deploy CCIP WETH9 Bridge..." -forge script script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-weth9-bridge.log | grep -E "CCIPWETH9Bridge deployed|deployed at:|Error" | head -3 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-weth9-bridge.log | grep -E "CCIPWETH9Bridge deployed|deployed at:|Error" | head -3 WETH9_BRIDGE=$(grep -oE "0x[a-fA-F0-9]{40}" /tmp/ccip-weth9-bridge.log 2>/dev/null | head -1) if [ -n "$WETH9_BRIDGE" ]; then echo " ✅ CCIP WETH9 Bridge: $WETH9_BRIDGE" @@ -117,7 +118,7 @@ fi echo "" echo "📋 2.5: Deploy CCIP WETH10 Bridge..." -forge script script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-weth10-bridge.log | grep -E "CCIPWETH10Bridge deployed|deployed at:|Error" | head -3 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/ccip-weth10-bridge.log | grep -E "CCIPWETH10Bridge deployed|deployed at:|Error" | head -3 WETH10_BRIDGE=$(grep -oE "0x[a-fA-F0-9]{40}" /tmp/ccip-weth10-bridge.log 2>/dev/null | head -1) if [ -n "$WETH10_BRIDGE" ]; then echo " ✅ CCIP WETH10 Bridge: $WETH10_BRIDGE" @@ -132,15 +133,15 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━ echo "" echo "📋 3.1: Deploy Multicall..." -forge script script/DeployMulticall.s.sol:DeployMulticall --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/multicall.log | grep -E "Multicall deployed|deployed at:|Error" | head -3 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployMulticall.s.sol:DeployMulticall --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/multicall.log | grep -E "Multicall deployed|deployed at:|Error" | head -3 echo "" echo "📋 3.2: Deploy Oracle..." -forge script script/DeployOracle.s.sol:DeployOracle --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/oracle.log | grep -E "Aggregator|Proxy|deployed at:|Error" | head -5 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployOracle.s.sol:DeployOracle --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/oracle.log | grep -E "Aggregator|Proxy|deployed at:|Error" | head -5 echo "" echo "📋 3.3: Deploy MultiSig..." -forge script script/DeployMultiSig.s.sol:DeployMultiSig --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/multisig.log | grep -E "MultiSig|deployed at:|Error" | head -3 +"${FORGE_SCOPE_RUNNER[@]}" script script/DeployMultiSig.s.sol:DeployMultiSig --rpc-url "$RPC_URL" --broadcast --private-key "$PRIVATE_KEY" --legacy -vvv 2>&1 | tee /tmp/multisig.log | grep -E "MultiSig|deployed at:|Error" | head -3 echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" diff --git a/scripts/deployment/deploy-contracts-ordered.sh b/scripts/deployment/deploy-contracts-ordered.sh index ec110a2..c796921 100755 --- a/scripts/deployment/deploy-contracts-ordered.sh +++ b/scripts/deployment/deploy-contracts-ordered.sh @@ -80,7 +80,7 @@ deploy_contract() { log_warn "Deploying ${contract_name}..." # Run deployment script - local output=$(forge script "$script_name" \ + local output=$(forge_scoped script "$script_name" \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -132,7 +132,7 @@ if [ -z "$CCIP_ROUTER" ] || [ "$CCIP_ROUTER" = "0x000000000000000000000000000000 log_warn "Warning: CCIP_FEE_TOKEN not set. Using zero address (native token)" fi - CCIP_ROUTER_ADDRESS=$(forge script script/DeployCCIPRouter.s.sol:DeployCCIPRouter \ + CCIP_ROUTER_ADDRESS=$(forge_scoped script script/DeployCCIPRouter.s.sol:DeployCCIPRouter \ --sig "run(address,uint256,uint256)" "$FEE_TOKEN" "$BASE_FEE" "$DATA_FEE_PER_BYTE" \ --rpc-url "$RPC_URL" \ --broadcast \ @@ -269,4 +269,3 @@ log_success "Oracle Aggregator: ${ORACLE_ADDRESS}" log_success "=== Deployment Complete ===" log_success "All contract addresses have been updated in .env file" - diff --git a/scripts/deployment/deploy-contracts-parallel.sh b/scripts/deployment/deploy-contracts-parallel.sh index e02a610..4753446 100755 --- a/scripts/deployment/deploy-contracts-parallel.sh +++ b/scripts/deployment/deploy-contracts-parallel.sh @@ -89,7 +89,7 @@ log_warn "Phase 1: Deploying independent contracts in parallel..." # Deploy Multicall, WETH9, and WETH10 in parallel { log_warn "Deploying Multicall..." - MULTICALL_OUTPUT=$(forge script script/DeployMulticall.s.sol:DeployMulticall \ + MULTICALL_OUTPUT=$(forge_scoped script script/DeployMulticall.s.sol:DeployMulticall \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -104,7 +104,7 @@ MULTICALL_PID=$! { log_warn "Deploying WETH9..." - WETH9_OUTPUT=$(forge script script/DeployWETH.s.sol:DeployWETH \ + WETH9_OUTPUT=$(forge_scoped script script/DeployWETH.s.sol:DeployWETH \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -119,7 +119,7 @@ WETH9_PID=$! { log_warn "Deploying WETH10..." - WETH10_OUTPUT=$(forge script script/DeployWETH10.s.sol:DeployWETH10 \ + WETH10_OUTPUT=$(forge_scoped script script/DeployWETH10.s.sol:DeployWETH10 \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -143,7 +143,7 @@ source .env # Phase 2: CCIP Router (if needed) if [ -z "$CCIP_ROUTER" ] || [ "$CCIP_ROUTER" = "0x0000000000000000000000000000000000000000" ]; then log_warn "Phase 2: Deploying CCIP Router..." - CCIP_ROUTER_OUTPUT=$(forge script script/DeployCCIPRouter.s.sol:DeployCCIPRouter \ + CCIP_ROUTER_OUTPUT=$(forge_scoped script script/DeployCCIPRouter.s.sol:DeployCCIPRouter \ --sig "run(address,uint256,uint256)" \ "$CCIP_FEE_TOKEN" \ "1000000000000000" \ @@ -171,7 +171,7 @@ if [ "${DEPLOY_BRIDGES:-true}" = "true" ] && [ -n "$CCIP_ROUTER" ] && [ -n "$WET { log_warn "Deploying CCIPWETH9Bridge..." export CCIP_ROUTER WETH9_ADDRESS CCIP_FEE_TOKEN - BRIDGE9_OUTPUT=$(forge script script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge \ + BRIDGE9_OUTPUT=$(forge_scoped script script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -187,7 +187,7 @@ if [ "${DEPLOY_BRIDGES:-true}" = "true" ] && [ -n "$CCIP_ROUTER" ] && [ -n "$WET { log_warn "Deploying CCIPWETH10Bridge..." export CCIP_ROUTER WETH10_ADDRESS CCIP_FEE_TOKEN - BRIDGE10_OUTPUT=$(forge script script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge \ + BRIDGE10_OUTPUT=$(forge_scoped script script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -212,7 +212,7 @@ log_warn "Phase 4: Deploying Oracle and MultiSig in parallel..." # Deploy Oracle (independent) { export ORACLE_DESCRIPTION ORACLE_HEARTBEAT ORACLE_DEVIATION_THRESHOLD - ORACLE_OUTPUT=$(forge script script/DeployOracle.s.sol:DeployOracle \ + ORACLE_OUTPUT=$(forge_scoped script script/DeployOracle.s.sol:DeployOracle \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -241,7 +241,7 @@ if [ -z "$MULTISIG_OWNERS" ]; then else { export OWNERS="$MULTISIG_OWNERS" - MULTISIG_OUTPUT=$(forge script script/DeployMultiSig.s.sol:DeployMultiSig \ + MULTISIG_OUTPUT=$(forge_scoped script script/DeployMultiSig.s.sol:DeployMultiSig \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ @@ -279,4 +279,3 @@ log_success "MultiSig: ${MULTISIG_ADDRESS:-N/A}" log_success "" log_success "=== Parallel Deployment Complete ===" log_success "All addresses have been updated in .env file" - diff --git a/scripts/deployment/deploy-contracts-unified.sh b/scripts/deployment/deploy-contracts-unified.sh index f000931..26a725a 100755 --- a/scripts/deployment/deploy-contracts-unified.sh +++ b/scripts/deployment/deploy-contracts-unified.sh @@ -8,6 +8,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/../lib/init.sh" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" cd "$PROJECT_ROOT" +FORGE_SCOPE_RUNNER=(bash "$PROJECT_ROOT/scripts/forge/scope.sh") # Load .env via dotenv (RPC CR/LF trim). Fallback: raw source. if [[ -f "$SCRIPT_DIR/../lib/deployment/dotenv.sh" ]]; then # shellcheck disable=SC1090 @@ -146,7 +147,7 @@ deploy_contract() { return fi - forge script "$script" \ + "${FORGE_SCOPE_RUNNER[@]}" script "$script" \ --rpc-url "$RPC_URL" \ --broadcast \ --private-key "$PRIVATE_KEY" \ diff --git a/scripts/deployment/deploy-optional-future-all.sh b/scripts/deployment/deploy-optional-future-all.sh index 8f54d17..1cc935f 100755 --- a/scripts/deployment/deploy-optional-future-all.sh +++ b/scripts/deployment/deploy-optional-future-all.sh @@ -108,44 +108,44 @@ echo "" # Phase 1: CREATE2 / Deterministic core run_phase 1 "Deterministic core (DeployDeterministicCore)" "CREATE2_FACTORY" \ - "forge script script/deploy/DeployDeterministicCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/deploy/DeployDeterministicCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 2: Vault system run_phase 2 "Vault system (DeployVaultSystem)" "VAULT_FACTORY" \ - "forge script script/deploy/vault/DeployVaultSystem.s.sol:DeployVaultSystem --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/deploy/vault/DeployVaultSystem.s.sol:DeployVaultSystem --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 3: Reserve system (requires TOKEN_FACTORY) run_phase 3 "Reserve system (DeployReserveSystem)" "RESERVE_SYSTEM" \ - "forge script script/reserve/DeployReserveSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/reserve/DeployReserveSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 4: Reserve Keeper (requires ORACLE_PRICE_FEED unless RESERVE_KEEPER already set) run_phase 4 "Reserve Keeper (DeployKeeper)" "RESERVE_KEEPER" \ - "forge script script/reserve/DeployKeeper.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" \ + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/reserve/DeployKeeper.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" \ "ORACLE_PRICE_FEED" # Phase 5: PaymentChannelManager + GenericStateChannelManager run_phase 5a "PaymentChannelManager" "PAYMENT_CHANNEL_MANAGER" \ - "forge script script/DeployPaymentChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/DeployPaymentChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" run_phase 5b "GenericStateChannelManager" "GENERIC_STATE_CHANNEL_MANAGER" \ - "forge script script/DeployGenericStateChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/DeployGenericStateChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 6: Trustless bridge (Lockbox138 on Chain 138) run_phase 6 "Trustless bridge (Lockbox138)" "LOCKBOX_138" \ - "forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 7: DODO / Swap (requires DODO_VENDING_MACHINE_ADDRESS, COMPLIANT_USDT_ADDRESS, COMPLIANT_USDC_ADDRESS) run_phase 7 "DODO PMM Integration" "DODOPMM_INTEGRATION_ADDRESS" \ - "forge script script/dex/DeployDODOPMMIntegration.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" \ + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/dex/DeployDODOPMMIntegration.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" \ "DODO_VENDING_MACHINE_ADDRESS" # Phase 8: eMoney (Chain 138) run_phase 8 "eMoney (DeployChain138)" "TOKEN_FACTORY_138" \ - "forge script script/emoney/DeployChain138.s.sol:DeployChain138 --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/emoney/DeployChain138.s.sol:DeployChain138 --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" # Phase 9: Smart accounts (informational — actual deploy from ERC-4337 impl) run_phase 9 "Smart accounts kit (informational)" "" \ - "forge script script/smart-accounts/DeploySmartAccountsKit.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" + "bash \"$PROJECT_ROOT/scripts/forge/scope.sh\" script script/smart-accounts/DeploySmartAccountsKit.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" echo "" echo "============================================" diff --git a/scripts/deployment/deploy-tokenization.sh b/scripts/deployment/deploy-tokenization.sh index 3db7715..b97ad47 100755 --- a/scripts/deployment/deploy-tokenization.sh +++ b/scripts/deployment/deploy-tokenization.sh @@ -3,6 +3,11 @@ set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true + # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' @@ -11,10 +16,11 @@ NC='\033[0m' # No Color # Configuration FABRIC_NETWORK="${FABRIC_NETWORK:-fabric-network}" -CHAIN_138_RPC_URL="${CHAIN_138_RPC_URL:-http://localhost:8545}" +CHAIN_138_RPC_URL="${CHAIN_138_RPC_URL:-${RPC_URL_138:-http://localhost:8545}}" FIREFLY_API_URL="${FIREFLY_API_URL:-http://localhost:5000}" CACTI_API_URL="${CACTI_API_URL:-http://localhost:4000}" INDY_API_URL="${INDY_API_URL:-http://localhost:9000}" +DEPLOYER_PRIVATE_KEY="${DEPLOYER_PRIVATE_KEY:-${PRIVATE_KEY:-}}" echo -e "${GREEN}Deploying Tokenization System...${NC}" @@ -61,6 +67,18 @@ if [ -z "$DEPLOYER_PRIVATE_KEY" ]; then exit 1 fi +for required_script in \ + script/tokenization/DeployTokenizedEUR.s.sol \ + script/tokenization/DeployTokenRegistry.s.sol \ + script/tokenization/RegisterToken.s.sol +do + if [ ! -f "$required_script" ]; then + echo -e "${RED}Error: missing required script $required_script${NC}" + echo -e "${YELLOW}This deployment wrapper is stale relative to the current repo layout and needs refreshed tokenization scripts before it can run.${NC}" + exit 1 + fi +done + TOKENIZED_EUR_ADDRESS=$(forge script script/tokenization/DeployTokenizedEUR.s.sol \ --rpc-url "$CHAIN_138_RPC_URL" \ --private-key "$DEPLOYER_PRIVATE_KEY" \ diff --git a/scripts/deployment/dry-run-enhanced-swap-router-chain138.sh b/scripts/deployment/dry-run-enhanced-swap-router-chain138.sh index a5af45b..8814694 100644 --- a/scripts/deployment/dry-run-enhanced-swap-router-chain138.sh +++ b/scripts/deployment/dry-run-enhanced-swap-router-chain138.sh @@ -50,6 +50,7 @@ elif [[ -f "$ENV_FILE" ]]; then set +a ENV_SOURCE="$ENV_FILE" fi +source "$SMOM_ROOT/scripts/lib/forge-scope.sh" RPC_URL_138="${RPC_URL_138:-http://192.168.11.211:8545}" WETH="${WETH:-$CHAIN138_WETH_DEFAULT}" @@ -231,9 +232,9 @@ echo "" echo "Exact dry-run command" if [[ -f "$PROJECT_ENV_LOADER" ]]; then - echo "cd \"$PROJECT_ROOT\" && source scripts/lib/load-project-env.sh && cd smom-dbis-138 && forge script script/bridge/trustless/DeployEnhancedSwapRouter.s.sol:DeployEnhancedSwapRouter --rpc-url \"$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\"" + echo "cd \"$PROJECT_ROOT\" && source scripts/lib/load-project-env.sh && cd smom-dbis-138 && bash scripts/forge/scope.sh script bridge/trustless script/bridge/trustless/DeployEnhancedSwapRouter.s.sol:DeployEnhancedSwapRouter --rpc-url \"$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\"" else - echo "cd \"$SMOM_ROOT\" && source .env && forge script script/bridge/trustless/DeployEnhancedSwapRouter.s.sol:DeployEnhancedSwapRouter --rpc-url \"$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\"" + echo "cd \"$SMOM_ROOT\" && source .env && bash scripts/forge/scope.sh script bridge/trustless script/bridge/trustless/DeployEnhancedSwapRouter.s.sol:DeployEnhancedSwapRouter --rpc-url \"$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\"" fi echo "" echo "Example minimal exports before dry-run" diff --git a/scripts/deployment/dry-run-enhanced-swap-router-v2-chain138.sh b/scripts/deployment/dry-run-enhanced-swap-router-v2-chain138.sh index 708f015..7e159f4 100644 --- a/scripts/deployment/dry-run-enhanced-swap-router-v2-chain138.sh +++ b/scripts/deployment/dry-run-enhanced-swap-router-v2-chain138.sh @@ -45,6 +45,7 @@ elif [[ -f "$ENV_FILE" ]]; then set +a ENV_SOURCE="$ENV_FILE" fi +source "$SMOM_ROOT/scripts/lib/forge-scope.sh" RPC_URL_138="${RPC_URL_138:-http://192.168.11.211:8545}" WETH="${WETH:-0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2}" diff --git a/scripts/deployment/final-mainnet-deployment-report.sh b/scripts/deployment/final-mainnet-deployment-report.sh index 5ef5b96..4e0f8f9 100755 --- a/scripts/deployment/final-mainnet-deployment-report.sh +++ b/scripts/deployment/final-mainnet-deployment-report.sh @@ -3,7 +3,11 @@ set -e -cd "$(dirname "$0")/../.." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$SCRIPT_DIR/../lib/init.sh" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true # Color codes @@ -49,8 +53,8 @@ declare -A CONTRACT_DEPS=( declare -A CONTRACT_SCRIPTS=( ["CCIPLogger"]="npx hardhat run scripts/ccip-deployment/deploy-ccip-logger.js --network mainnet" - ["CCIPWETH9Bridge"]="forge script script/DeployCCIPWETH9Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" - ["CCIPWETH10Bridge"]="forge script script/DeployCCIPWETH10Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" + ["CCIPWETH9Bridge"]="bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" + ["CCIPWETH10Bridge"]="bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" ) TOTAL_COST_WEI=0 @@ -80,7 +84,7 @@ COSTS["CCIPWETH9Bridge"]=$cost_eth TOTAL_COST_WEI=$(echo "$TOTAL_COST_WEI + $cost_wei" | bc 2>/dev/null) echo " Estimated Cost: $cost_eth ETH" echo " Dependencies: CCIPRouter" -echo " Script: forge script script/DeployCCIPWETH9Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" +echo " Script: bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" echo "3. CCIPWETH10Bridge" echo " Location: contracts/ccip/CCIPWETH10Bridge.sol" @@ -93,7 +97,7 @@ COSTS["CCIPWETH10Bridge"]=$cost_eth TOTAL_COST_WEI=$(echo "$TOTAL_COST_WEI + $cost_wei" | bc 2>/dev/null) echo " Estimated Cost: $cost_eth ETH" echo " Dependencies: CCIPRouter" -echo " Script: forge script script/DeployCCIPWETH10Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" +echo " Script: bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" TOTAL_COST_ETH=$(echo "scale=10; $TOTAL_COST_WEI / 1000000000000000000" | bc 2>/dev/null) diff --git a/scripts/deployment/generate-prioritized-deployment-plan.sh b/scripts/deployment/generate-prioritized-deployment-plan.sh index e19e231..185666e 100755 --- a/scripts/deployment/generate-prioritized-deployment-plan.sh +++ b/scripts/deployment/generate-prioritized-deployment-plan.sh @@ -3,7 +3,11 @@ set -e -cd "$(dirname "$0")/../.." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$SCRIPT_DIR/../lib/init.sh" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true # Color codes @@ -35,8 +39,8 @@ declare -A CONTRACT_DEPS=( declare -A CONTRACT_SCRIPTS=( ["CCIPLogger"]="npx hardhat run scripts/ccip-deployment/deploy-ccip-logger.js --network mainnet" - ["CCIPWETH9Bridge"]="forge script script/DeployCCIPWETH9Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" - ["CCIPWETH10Bridge"]="forge script script/DeployCCIPWETH10Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" + ["CCIPWETH9Bridge"]="bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" + ["CCIPWETH10Bridge"]="bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" ) log_success "Remaining Contracts for Mainnet Deployment:" diff --git a/scripts/deployment/inventory-register-dodo-pools-chain138.sh b/scripts/deployment/inventory-register-dodo-pools-chain138.sh index 4b2c06c..c78786c 100644 --- a/scripts/deployment/inventory-register-dodo-pools-chain138.sh +++ b/scripts/deployment/inventory-register-dodo-pools-chain138.sh @@ -5,12 +5,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SMOM_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" ENV_FILE="$SMOM_ROOT/.env" -if [[ -f "$ENV_FILE" ]]; then - set -a - # shellcheck disable=SC1090 - source "$ENV_FILE" - set +a -fi +source "$SMOM_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true RPC_URL_138="${RPC_URL_138:-http://192.168.11.211:8545}" DODO_PMM_INTEGRATION_ADDRESS="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-}}" @@ -114,7 +109,7 @@ for pool in "${pools[@]}"; do done echo "Dry-run command:" -echo " cd \"$SMOM_ROOT\" && source .env && bash scripts/deployment/inventory-register-dodo-pools-chain138.sh" +echo " cd \"$SMOM_ROOT\" && source scripts/load-env.sh && bash scripts/deployment/inventory-register-dodo-pools-chain138.sh" echo "" echo "Broadcast command:" -echo " cd \"$SMOM_ROOT\" && source .env && forge script script/liquidity/RegisterDODOPools.s.sol:RegisterDODOPools --rpc-url \"\$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\" --broadcast --slow --with-gas-price 1000000000" +echo " cd \"$SMOM_ROOT\" && source scripts/load-env.sh && bash scripts/forge/scope.sh script liquidity script/liquidity/RegisterDODOPools.s.sol:RegisterDODOPools --rpc-url \"\$RPC_URL_138\" --private-key \"\$PRIVATE_KEY\" --broadcast --slow --with-gas-price 1000000000" diff --git a/scripts/deployment/list-remaining-mainnet-contracts.sh b/scripts/deployment/list-remaining-mainnet-contracts.sh index 82320f2..ad83662 100755 --- a/scripts/deployment/list-remaining-mainnet-contracts.sh +++ b/scripts/deployment/list-remaining-mainnet-contracts.sh @@ -39,12 +39,10 @@ echo " - WETH10: Predeployed at 0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f" echo " - Status: Already exist on Mainnet (no deployment needed)" log_info "4. CCIPTxReporter" -echo " - CCIPTxReporter.sol (Chain-138 sender)" -echo " Location: contracts/ccip-integration/CCIPTxReporter.sol" -echo " Deployment: Hardhat script" -echo " Script: scripts/ccip-deployment/deploy-ccip-reporter.js" -echo " Status: Deploys to Chain-138 (not Mainnet)" -echo " Note: This contract is deployed on Chain-138, not Mainnet" +echo " - Historical Chain-138 sender" +echo " Source archive: archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol" +echo " Status: Not part of the active Mainnet deployment set" +echo " Note: Use CHAIN138_CCIP_REPORTER for the existing deployment if this flow is still needed" log_warn "Summary:" echo " Total contracts for Mainnet: 3" diff --git a/scripts/deployment/phase2-deploy-core.sh b/scripts/deployment/phase2-deploy-core.sh index 2f3619f..5c61b94 100755 --- a/scripts/deployment/phase2-deploy-core.sh +++ b/scripts/deployment/phase2-deploy-core.sh @@ -5,12 +5,12 @@ set -e -echo "=== Phase 2: Deploy Core Bridge Contracts ===" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true -# Load environment variables -if [ -f .env ]; then - export $(cat .env | grep -v '^#' | grep -v '^$' | xargs) -fi +echo "=== Phase 2: Deploy Core Bridge Contracts ===" # Check required variables REQUIRED_VARS=( @@ -72,4 +72,3 @@ echo "" echo "=== Phase 2 Complete ===" echo "Core bridge contracts deployed" echo "⚠️ Remember to update .env with all contract addresses" - diff --git a/scripts/deployment/phase3-deploy-router.sh b/scripts/deployment/phase3-deploy-router.sh index 53eb2f5..0674ff0 100755 --- a/scripts/deployment/phase3-deploy-router.sh +++ b/scripts/deployment/phase3-deploy-router.sh @@ -5,12 +5,12 @@ set -e -echo "=== Phase 3: Deploy EnhancedSwapRouter ===" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true -# Load environment variables -if [ -f .env ]; then - export $(cat .env | grep -v '^#' | grep -v '^$' | xargs) -fi +echo "=== Phase 3: Deploy EnhancedSwapRouter ===" # Check required variables REQUIRED_VARS=( @@ -55,4 +55,3 @@ echo "" echo "=== Phase 3 Complete ===" echo "EnhancedSwapRouter deployed" echo "⚠️ Remember to update .env with ENHANCED_SWAP_ROUTER address" - diff --git a/scripts/deployment/phase4-deploy-integration.sh b/scripts/deployment/phase4-deploy-integration.sh index 304c2e9..bc7d5bb 100755 --- a/scripts/deployment/phase4-deploy-integration.sh +++ b/scripts/deployment/phase4-deploy-integration.sh @@ -5,12 +5,12 @@ set -e -echo "=== Phase 4: Deploy Integration Contracts ===" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true -# Load environment variables -if [ -f .env ]; then - export $(cat .env | grep -v '^#' | grep -v '^$' | xargs) -fi +echo "=== Phase 4: Deploy Integration Contracts ===" # Check required variables REQUIRED_VARS=( @@ -52,4 +52,3 @@ echo "" echo "=== Phase 4 Complete ===" echo "Integration contracts deployed" echo "⚠️ Remember to update .env with all contract addresses" - diff --git a/scripts/deployment/phase5-initialize.sh b/scripts/deployment/phase5-initialize.sh index 0d6507e..c8e39f8 100755 --- a/scripts/deployment/phase5-initialize.sh +++ b/scripts/deployment/phase5-initialize.sh @@ -5,12 +5,12 @@ set -e -echo "=== Phase 5: Initialize System ===" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true -# Load environment variables -if [ -f .env ]; then - export $(cat .env | grep -v '^#' | grep -v '^$' | xargs) -fi +echo "=== Phase 5: Initialize System ===" # Check required variables REQUIRED_VARS=( @@ -39,4 +39,3 @@ forge script script/bridge/trustless/InitializeBridgeSystem.s.sol:InitializeBrid echo "" echo "=== Phase 5 Complete ===" echo "System initialized and configured" - diff --git a/scripts/deployment/prioritize-mainnet-deployments.sh b/scripts/deployment/prioritize-mainnet-deployments.sh index 35e48d8..022e1ef 100755 --- a/scripts/deployment/prioritize-mainnet-deployments.sh +++ b/scripts/deployment/prioritize-mainnet-deployments.sh @@ -3,7 +3,11 @@ set -e -cd "$(dirname "$0")/../.." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$SCRIPT_DIR/../lib/init.sh" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true echo "=== Mainnet Deployment Prioritization ===" @@ -32,8 +36,8 @@ declare -A CONTRACT_DEPS=( # Contract deployment scripts declare -A CONTRACT_SCRIPTS=( ["CCIPLogger"]="npx hardhat run scripts/ccip-deployment/deploy-ccip-logger.js --network mainnet" - ["CCIPWETH9Bridge"]="forge script script/DeployCCIPWETH9Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" - ["CCIPWETH10Bridge"]="forge script script/DeployCCIPWETH10Bridge.s.sol --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" + ["CCIPWETH9Bridge"]="bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH9Bridge.s.sol:DeployCCIPWETH9Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" + ["CCIPWETH10Bridge"]="bash scripts/forge/scope.sh script ccip script/DeployCCIPWETH10Bridge.s.sol:DeployCCIPWETH10Bridge --rpc-url \$ETHEREUM_MAINNET_RPC --broadcast --private-key \$PRIVATE_KEY" ) log_info "Wallet Balance: $WALLET_BALANCE ETH" diff --git a/scripts/deployment/setup-chain138-env.sh b/scripts/deployment/setup-chain138-env.sh index 490c262..301805c 100755 --- a/scripts/deployment/setup-chain138-env.sh +++ b/scripts/deployment/setup-chain138-env.sh @@ -58,5 +58,6 @@ fi log_success "✅ Chain-138 environment setup complete" echo "Next steps:" echo " 1. Verify RPC connectivity: ./scripts/deployment/verify-chain138-full-deployment.sh" -echo " 2. Deploy CCIPTxReporter: npm run deploy:reporter:chain138" +echo " 2. If you use the historical CCIPTxReporter flow, set CHAIN138_CCIP_REPORTER in .env" +echo " Source archive: archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol" echo " 3. Run verification: ./scripts/deployment/verify-chain138-complete.sh" diff --git a/scripts/forge/report-contract-reachability.py b/scripts/forge/report-contract-reachability.py new file mode 100755 index 0000000..7e5e77b --- /dev/null +++ b/scripts/forge/report-contract-reachability.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +"""Report Solidity contracts that are not reachable from current tests or scripts.""" + +from __future__ import annotations + +import argparse +import json +import re +import sys +from collections import Counter +from pathlib import Path + + +EXCLUDED_PARTS = {"artifacts", "broadcast", "cache", "lib", "node_modules", "out"} +IMPORT_RE = re.compile(r'^\s*import\s+(?:\{[^}]+\}\s+from\s+)?["\']([^"\']+)["\'];', re.M) + + +def discover_sources(repo_root: Path) -> dict[str, Path]: + return { + path.relative_to(repo_root).as_posix(): path + for path in repo_root.rglob("*.sol") + if path.is_file() and not any(part in EXCLUDED_PARTS for part in path.parts) + } + + +def resolve_import(importer: Path, import_path: str, repo_root: Path) -> str | None: + if import_path.startswith(("./", "../")): + target = (importer.parent / import_path).resolve() + try: + return target.relative_to(repo_root).as_posix() + except ValueError: + return None + + if import_path.startswith("@emoney/"): + return f"contracts/emoney/{import_path[len('@emoney/'):]}" + + return None + + +def build_graph(repo_root: Path, files: dict[str, Path]) -> tuple[dict[str, list[str]], dict[str, set[str]]]: + imports: dict[str, list[str]] = {} + inbound: dict[str, set[str]] = {rel: set() for rel in files} + + for rel_path, file_path in files.items(): + text = file_path.read_text(errors="ignore") + resolved_targets: list[str] = [] + for import_path in IMPORT_RE.findall(text): + target = resolve_import(file_path, import_path, repo_root) + if target and target in files: + resolved_targets.append(target) + inbound[target].add(rel_path) + imports[rel_path] = resolved_targets + + return imports, inbound + + +def walk_reachable(imports: dict[str, list[str]], roots: list[str]) -> set[str]: + seen: set[str] = set() + stack = list(roots) + while stack: + current = stack.pop() + if current in seen: + continue + seen.add(current) + stack.extend(imports.get(current, [])) + return seen + + +def create_report(repo_root: Path) -> dict[str, object]: + files = discover_sources(repo_root) + imports, inbound = build_graph(repo_root, files) + + contract_files = sorted(rel for rel in files if rel.startswith("contracts/")) + root_files = sorted(rel for rel in files if rel.startswith(("test/", "script/"))) + reachable = walk_reachable(imports, root_files) + + unreachable = [rel for rel in contract_files if rel not in reachable] + no_inbound = [rel for rel in contract_files if not inbound[rel]] + + unreachable_by_bucket = Counter(path.split("/")[1] for path in unreachable) + no_inbound_by_bucket = Counter(path.split("/")[1] for path in no_inbound) + + return { + "repoRoot": repo_root.as_posix(), + "summary": { + "contractsTotal": len(contract_files), + "rootsTotal": len(root_files), + "contractsReachableFromTestsOrScripts": len(contract_files) - len(unreachable), + "contractsUnreachableFromTestsOrScripts": len(unreachable), + "contractsWithNoLocalInboundRefs": len(no_inbound), + }, + "unreachableByBucket": dict(unreachable_by_bucket.most_common()), + "noInboundByBucket": dict(no_inbound_by_bucket.most_common()), + "unreachableContracts": unreachable, + "contractsWithNoLocalInboundRefs": no_inbound, + } + + +def print_text(report: dict[str, object]) -> None: + summary = report["summary"] + print(f"repo root: {report['repoRoot']}") + print(f"contracts total: {summary['contractsTotal']}") + print(f"tests/scripts roots total: {summary['rootsTotal']}") + print(f"contracts reachable from tests or scripts: {summary['contractsReachableFromTestsOrScripts']}") + print(f"contracts unreachable from tests or scripts: {summary['contractsUnreachableFromTestsOrScripts']}") + print(f"contracts with no local inbound refs: {summary['contractsWithNoLocalInboundRefs']}") + print() + print("Unreachable by top-level bucket:") + for bucket, count in report["unreachableByBucket"].items(): + print(f" {bucket}: {count}") + print() + print("Archive candidates (unreachable from current tests/scripts):") + for contract in report["unreachableContracts"]: + print(f" {contract}") + print() + print("Note: unreachable does not prove safe deletion; it only means this repo's current Solidity tests/scripts do not import the file.") + + +def parse_args(argv: list[str]) -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--json", action="store_true", help="emit machine-readable JSON") + return parser.parse_args(argv) + + +def main(argv: list[str]) -> int: + args = parse_args(argv) + repo_root = Path(__file__).resolve().parents[2] + report = create_report(repo_root) + + if args.json: + json.dump(report, sys.stdout, indent=2) + sys.stdout.write("\n") + return 0 + + print_text(report) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv[1:])) diff --git a/scripts/forge/scope.sh b/scripts/forge/scope.sh new file mode 100755 index 0000000..b6d964d --- /dev/null +++ b/scripts/forge/scope.sh @@ -0,0 +1,324 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +REPO_ROOT=$(cd "$SCRIPT_DIR/../.." && pwd) + +declare -A ROOT_SCRIPT_SCOPE_ALIASES=( + ["DeployAddressMapper.s.sol"]="utils" + ["DeployAddressMapperOtherChain.s.sol"]="utils" + ["DeployCCIPRouter.s.sol"]="ccip" + ["DeployCCIPSender.s.sol"]="ccip" + ["DeployCCIPSenderMainnet.s.sol"]="ccip" + ["DeployCCIPReceiver.s.sol"]="ccip" + ["DeployCCIPReceiverMainnet.s.sol"]="ccip" + ["DeployCCIPRelay.s.sol"]="relay" + ["DeployCCIPWETH9Bridge.s.sol"]="ccip" + ["DeployCCIPWETH10Bridge.s.sol"]="ccip" + ["DeployComplianceRegistry.s.sol"]="compliance" + ["DeployCompliantUSDC.s.sol"]="tokens" + ["DeployCompliantUSDT.s.sol"]="tokens" + ["DeployCWAssetReserveVerifier.s.sol"]="bridge/integration" + ["DeployCWReserveVerifier.s.sol"]="bridge/integration" + ["DeployFeeCollector.s.sol"]="utils" + ["DeployGenericStateChannelManager.s.sol"]="channels" + ["DeployMainnetTether.s.sol"]="tether" + ["DeployMirrorManager.s.sol"]="mirror" + ["DeployMulticall.s.sol"]="utils" + ["DeployMultiSig.s.sol"]="governance" + ["DeployOfficialUSDC138.s.sol"]="tokens" + ["DeployOfficialUSDT138.s.sol"]="tokens" + ["DeployOracle.s.sol"]="oracle" + ["DeployPaymentChannelManager.s.sol"]="channels" + ["DeployTokenRegistry.s.sol"]="utils" + ["DeployTransactionMirror.s.sol"]="mirror" + ["DeployWETH.s.sol"]="tokens" + ["DeployWETH10.s.sol"]="tokens" + ["DeployWETHWithCCIP.s.sol"]="full" +) + +usage() { + cat <<'EOF' +Usage: + bash scripts/forge/scope.sh list + bash scripts/forge/scope.sh build [scope] [forge build args...] + bash scripts/forge/scope.sh test [scope] [forge test args...] + bash scripts/forge/scope.sh script [scope] [forge script args...] + bash scripts/forge/scope.sh orphans [--json] + +Examples: + bash scripts/forge/scope.sh build treasury + bash scripts/forge/scope.sh test flash --match-path 'test/flash/*.t.sol' + bash scripts/forge/scope.sh script bridge/trustless script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url "$RPC_URL_138" + FORGE_SCOPE=vault bash scripts/forge/scope.sh test --match-path 'test/vault/*.t.sol' + +Notes: + - Omit [scope] to use FORGE_SCOPE, otherwise default to 'full'. + - 'full' preserves the historical repo-wide Forge behavior. + - Any other scope is resolved relative to contracts/, for example: + treasury -> contracts/treasury + bridge/trustless -> contracts/bridge/trustless + - If no explicit scope is given, the runner tries to infer one from + script/test/build paths and common root-level deployment script names. +EOF +} + +die() { + echo "error: $*" >&2 + exit 1 +} + +info() { + echo "$*" >&2 +} + +resolve_scope() { + local raw="${1:-${FORGE_SCOPE:-full}}" + raw="${raw#contracts/}" + raw="${raw#/}" + if [[ -z "$raw" ]]; then + raw="full" + fi + printf '%s\n' "$raw" +} + +scope_label() { + printf '%s\n' "${1//\//-}" +} + +scope_exists() { + local scope="$1" + [[ "$scope" == "full" || -d "$REPO_ROOT/contracts/$scope" ]] +} + +infer_scope_from_script_alias() { + local raw="${1%%:*}" + local base + base=$(basename "$raw") + if [[ -n "${ROOT_SCRIPT_SCOPE_ALIASES[$base]:-}" ]]; then + printf '%s\n' "${ROOT_SCRIPT_SCOPE_ALIASES[$base]}" + return 0 + fi + return 1 +} + +infer_scope_from_script_imports() { + local raw="${1%%:*}" + local script_path="$REPO_ROOT/${raw#./}" + [[ -f "$script_path" ]] || return 1 + + python3 - "$REPO_ROOT" "$script_path" <<'PY' +from pathlib import Path +import re +import sys + +repo_root = Path(sys.argv[1]).resolve() +script_path = Path(sys.argv[2]).resolve() +text = script_path.read_text(errors="ignore") +imports = re.findall(r'^\s*import\s+(?:\{[^}]+\}\s+from\s+)?["\']([^"\']+)["\'];', text, re.M) + +for imp in imports: + if not imp.startswith(("./", "../")): + continue + candidate = (script_path.parent / imp).resolve() + try: + rel = candidate.relative_to(repo_root).as_posix() + except ValueError: + continue + if not rel.startswith("contracts/"): + continue + scope = rel[len("contracts/"):] + if candidate.is_file(): + scope = str(Path(scope).parent).replace("\\", "/") + scope = scope.strip(".") + while scope: + if (repo_root / "contracts" / scope).is_dir(): + print(scope) + raise SystemExit(0) + scope = scope.rsplit("/", 1)[0] if "/" in scope else "" + +raise SystemExit(1) +PY +} + +extract_scope_from_path() { + local raw="${1%%:*}" + raw="${raw#./}" + + case "$raw" in + contracts/*) + raw="${raw#contracts/}" + ;; + test/*) + raw="${raw#test/}" + ;; + script/*) + raw="${raw#script/}" + ;; + *) + return 1 + ;; + esac + + local candidate + for candidate in "$raw" "${raw#deploy/}"; do + [[ -n "$candidate" ]] || continue + + if [[ -d "$REPO_ROOT/contracts/$candidate" ]]; then + printf '%s\n' "$candidate" + return 0 + fi + + local probe="${candidate%/*}" + if [[ "$probe" != "$candidate" ]]; then + while [[ -n "$probe" ]]; do + if [[ -d "$REPO_ROOT/contracts/$probe" ]]; then + printf '%s\n' "$probe" + return 0 + fi + if [[ "$probe" != *"/"* ]]; then + break + fi + probe="${probe%/*}" + done + fi + done + + if [[ "$1" == script/* ]]; then + infer_scope_from_script_alias "$1" && return 0 + infer_scope_from_script_imports "$1" && return 0 + fi + + return 1 +} + +infer_scope_from_args() { + local arg inferred + for arg in "$@"; do + inferred=$(extract_scope_from_path "$arg" || true) + if [[ -n "$inferred" ]]; then + printf '%s\n' "$inferred" + return 0 + fi + done + return 1 +} + +list_scopes() { + ( + cd "$REPO_ROOT" + echo "full" + find contracts -mindepth 1 -maxdepth 2 -type d | sed 's#^contracts/##' | sort + ) +} + +prepare_scope_env() { + local scope="$1" + local command="$2" + + if [[ "$scope" == "full" ]]; then + return 0 + fi + + local src_dir="contracts/$scope" + [[ -d "$REPO_ROOT/$src_dir" ]] || die "unknown scope '$scope' (expected directory '$src_dir')" + + local label + label=$(scope_label "$scope") + + export FOUNDRY_SRC="$src_dir" + export FOUNDRY_OUT="out/scopes/$label" + export FOUNDRY_CACHE_PATH="cache/scopes/$label" + export FOUNDRY_SPARSE_MODE="${FOUNDRY_SPARSE_MODE:-true}" + + if [[ "$command" == "test" ]]; then + local test_dir="test/$scope" + if [[ -d "$REPO_ROOT/$test_dir" ]]; then + export FOUNDRY_TEST="$test_dir" + fi + fi + + if [[ "$command" == "script" ]]; then + local script_dir="script/$scope" + if [[ -d "$REPO_ROOT/$script_dir" ]]; then + export FOUNDRY_SCRIPT="$script_dir" + fi + fi +} + +main() { + cd "$REPO_ROOT" + + local command="${1:-}" + [[ -n "$command" ]] || { + usage + exit 1 + } + shift || true + + case "$command" in + help|-h|--help) + usage + ;; + list) + list_scopes + ;; + orphans) + exec python3 scripts/forge/report-contract-reachability.py "$@" + ;; + build|test|script) + local scope="" + if [[ $# -gt 0 && "$1" != --* ]]; then + local maybe_scope + maybe_scope=$(resolve_scope "$1") + if scope_exists "$maybe_scope"; then + scope="$maybe_scope" + shift + fi + fi + + if [[ -z "$scope" ]]; then + if [[ -n "${FORGE_SCOPE:-}" ]]; then + scope=$(resolve_scope) + else + scope=$(infer_scope_from_args "$@" || printf 'full\n') + fi + fi + + prepare_scope_env "$scope" "$command" + + if [[ "$scope" == "full" ]]; then + info "Forge scope: full repo" + else + info "Forge scope: $scope" + info " src=$FOUNDRY_SRC out=$FOUNDRY_OUT cache=$FOUNDRY_CACHE_PATH" + [[ -n "${FOUNDRY_TEST:-}" ]] && info " test=$FOUNDRY_TEST" + [[ -n "${FOUNDRY_SCRIPT:-}" ]] && info " script=$FOUNDRY_SCRIPT" + fi + + case "$command" in + build) + if [[ "$scope" == "full" ]]; then + exec forge build "$@" + fi + exec forge build --skip test --skip script "$@" + ;; + test) + if [[ "$scope" != "full" && -z "${FOUNDRY_TEST:-}" ]]; then + die "scope '$scope' has no matching test/ directory" + fi + exec forge test "$@" + ;; + script) + [[ $# -gt 0 ]] || die "script command requires a script target, e.g. script/treasury/DeployTreasuryExecutor138.s.sol:DeployTreasuryExecutor138" + exec forge script "$@" + ;; + esac + ;; + *) + die "unknown command '$command'" + ;; + esac +} + +main "$@" diff --git a/scripts/lib/deployment/dotenv.sh b/scripts/lib/deployment/dotenv.sh index b907f36..9f34a4a 100644 --- a/scripts/lib/deployment/dotenv.sh +++ b/scripts/lib/deployment/dotenv.sh @@ -9,7 +9,8 @@ # So: use repo-root .env by default; set ENV_FILE to use a different file. _LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -[[ -z "${PROJECT_ROOT:-}" ]] && PROJECT_ROOT="$(cd "$_LIB_DIR/../.." && pwd)" +[[ -z "${PROJECT_ROOT:-}" ]] && PROJECT_ROOT="$(cd "$_LIB_DIR/../../.." && pwd)" +source "$_LIB_DIR/../forge-scope.sh" # Preferred .env: ENV_FILE if set and readable; else PROJECT_ROOT/.env (repo root). load_deployment_env() { diff --git a/scripts/lib/forge-scope.sh b/scripts/lib/forge-scope.sh new file mode 100644 index 0000000..fd1df0f --- /dev/null +++ b/scripts/lib/forge-scope.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +if [[ -n "${FORGE_SCOPE_HELPER_LOADED:-}" ]]; then + return 0 +fi + +FORGE_SCOPE_HELPER_LOADED=1 + +forge_scope_repo_root() { + local helper_dir + helper_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + + if [[ -n "${PROJECT_ROOT:-}" ]]; then + printf '%s\n' "$PROJECT_ROOT" + return 0 + fi + + if [[ -n "${REPO_ROOT:-}" ]]; then + printf '%s\n' "$REPO_ROOT" + return 0 + fi + + printf '%s\n' "$(cd "$helper_dir/../.." && pwd)" +} + +forge_scoped() { + local root + root="$(forge_scope_repo_root)" + bash "$root/scripts/forge/scope.sh" "$@" +} + +forge() { + if [[ $# -gt 0 ]]; then + case "$1" in + build|test|script) + local subcommand="$1" + shift + forge_scoped "$subcommand" "$@" + return $? + ;; + esac + fi + + command forge "$@" +} diff --git a/scripts/lib/init.sh b/scripts/lib/init.sh index 64076f8..8f24796 100755 --- a/scripts/lib/init.sh +++ b/scripts/lib/init.sh @@ -31,9 +31,9 @@ source "${LIB_DIR}/common/error-handling.sh" 2>/dev/null || true source "${LIB_DIR}/config/env.sh" source "${LIB_DIR}/config/regions.sh" source "${LIB_DIR}/azure/cli.sh" 2>/dev/null || true +source "${LIB_DIR}/forge-scope.sh" # Log that libraries are loaded (only in debug mode) # Use default 1 if LOG_LEVEL is unset or not numeric (e.g. from .env) _ll="${LOG_LEVEL:-1}" [[ "$_ll" =~ ^[0-9]+$ ]] && [ "$_ll" -le 0 ] && log_debug "Common libraries loaded from ${LIB_DIR}" || true - diff --git a/scripts/mint-for-liquidity.sh b/scripts/mint-for-liquidity.sh index 571f7f6..0d624cf 100755 --- a/scripts/mint-for-liquidity.sh +++ b/scripts/mint-for-liquidity.sh @@ -16,8 +16,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" cd "$PROJECT_ROOT" - -[[ -f .env ]] && set -a && source .env && set +a +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true RPC="${RPC_URL_138:-${RPC_URL:-http://192.168.11.211:8545}}" CUSDT="${COMPLIANT_USDT:-0x93E66202A11B1772E55407B32B44e5Cd8eda7f22}" diff --git a/scripts/quick-compile-test.sh b/scripts/quick-compile-test.sh index d17c988..d709aa4 100644 --- a/scripts/quick-compile-test.sh +++ b/scripts/quick-compile-test.sh @@ -3,6 +3,7 @@ # Quick compilation test for TokenFactory138 cd /home/intlc/projects/proxmox/smom-dbis-138 +source scripts/lib/forge-scope.sh echo "Testing TokenFactory138 compilation..." @@ -29,4 +30,3 @@ else forge build --via-ir 2>&1 | grep -i "error" | head -10 exit 1 fi - diff --git a/scripts/reserve/keeper-service.sh b/scripts/reserve/keeper-service.sh index 9927f80..891535c 100755 --- a/scripts/reserve/keeper-service.sh +++ b/scripts/reserve/keeper-service.sh @@ -4,6 +4,11 @@ set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true + # Load environment variables if [ -f .env ]; then source .env @@ -106,4 +111,3 @@ main() { # Run main function main - diff --git a/scripts/reserve/setup-complete.sh b/scripts/reserve/setup-complete.sh index 6c595a4..2a46dbf 100755 --- a/scripts/reserve/setup-complete.sh +++ b/scripts/reserve/setup-complete.sh @@ -4,6 +4,11 @@ set -e +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +cd "$PROJECT_ROOT" +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true + echo "=== Complete Reserve System Setup ===" echo "" @@ -28,4 +33,3 @@ forge script script/reserve/ConfigureInitialReserves.s.sol:ConfigureInitialReser echo "" echo "=== Setup Complete ===" echo "Reserve System is now ready for operations" - diff --git a/scripts/run-lint-test-build-deploy.sh b/scripts/run-lint-test-build-deploy.sh index e61f251..3d27a92 100755 --- a/scripts/run-lint-test-build-deploy.sh +++ b/scripts/run-lint-test-build-deploy.sh @@ -5,9 +5,10 @@ set -e PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$PROJECT_ROOT" export FOUNDRY_PROFILE=default +FORGE_SCOPE="${FORGE_SCOPE:-full}" echo "=== 1. Compile ===" -forge build +bash scripts/forge/scope.sh build "$FORGE_SCOPE" echo "✅ Build OK" echo "" @@ -17,7 +18,7 @@ echo "✅ Lint done" echo "" echo "=== 3. Test ===" -forge test 2>&1 | tail -50 +bash scripts/forge/scope.sh test "$FORGE_SCOPE" 2>&1 | tail -50 echo "✅ Tests done" echo "" @@ -25,9 +26,9 @@ echo "=== 4. Deploy ===" if [[ "${1:-}" == "--deploy-live" ]]; then echo "Live deploy: run your preferred deploy script, e.g.:" echo " bash scripts/deployment/deploy-tokens-and-weth-all-chains-skip-canonical.sh" - echo " or: forge script script/deploy/DeployCWTokens.s.sol:DeployCWTokens --rpc-url \$RPC_URL --chain-id 138 --broadcast --private-key \$PRIVATE_KEY --legacy" + echo " or: bash scripts/forge/scope.sh script script/deploy/DeployCWTokens.s.sol:DeployCWTokens --rpc-url \$RPC_URL --chain-id 138 --broadcast --private-key \$PRIVATE_KEY --legacy" exit 0 fi echo "Dry-run: DeployCWTokens (simulation only)" -forge script script/deploy/DeployCWTokens.s.sol:DeployCWTokens --rpc-url "https://eth.llamarpc.com" --chain-id 1 2>&1 | tail -30 +bash scripts/forge/scope.sh script script/deploy/DeployCWTokens.s.sol:DeployCWTokens --rpc-url "https://eth.llamarpc.com" --chain-id 1 2>&1 | tail -30 echo "✅ Deploy dry-run done (no broadcast)" diff --git a/scripts/security/run-slither.sh b/scripts/security/run-slither.sh index 74e9859..ad881a7 100644 --- a/scripts/security/run-slither.sh +++ b/scripts/security/run-slither.sh @@ -33,7 +33,7 @@ CONTRACTS=( "contracts/governance/GovernanceController.sol" "contracts/liquidity/LiquidityManager.sol" "contracts/bridge/BridgeOrchestrator.sol" - "contracts/plugins/PluginRegistry.sol" + "contracts/ccip/CCIPRouter.sol" ) for contract in "${CONTRACTS[@]}"; do diff --git a/scripts/test-tokenfactory-compile.sh b/scripts/test-tokenfactory-compile.sh index 40061ff..83319b7 100644 --- a/scripts/test-tokenfactory-compile.sh +++ b/scripts/test-tokenfactory-compile.sh @@ -5,6 +5,7 @@ set -e cd /home/intlc/projects/proxmox/smom-dbis-138 +source scripts/lib/forge-scope.sh echo "==========================================" echo "TokenFactory138 Compilation Test" @@ -109,4 +110,3 @@ else echo " Review logs: /tmp/tokenfactory-compile-*.log" fi echo "" - diff --git a/scripts/utils/get-mapped-address.sh b/scripts/utils/get-mapped-address.sh index 66889ee..42b9627 100755 --- a/scripts/utils/get-mapped-address.sh +++ b/scripts/utils/get-mapped-address.sh @@ -9,7 +9,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" cd "$PROJECT_ROOT" -source .env 2>/dev/null || true +source "$PROJECT_ROOT/scripts/load-env.sh" >/dev/null 2>&1 || true GENESIS_ADDRESS="${1:-}" @@ -26,7 +26,7 @@ ADDRESS_MAPPER="${ADDRESS_MAPPER:-}" if [ -z "$ADDRESS_MAPPER" ]; then echo "⚠️ ADDRESS_MAPPER not set in .env" - echo " Deploy AddressMapper first: forge script script/DeployAddressMapper.s.sol" + echo " Deploy AddressMapper first: bash scripts/forge/scope.sh script utils script/DeployAddressMapper.s.sol:DeployAddressMapper" echo "" echo "📋 Using static mapping from config/address-mapping.json..." @@ -62,4 +62,3 @@ else --rpc-url "${RPC_URL:-http://localhost:8545}" 2>/dev/null | \ grep -oE "0x[a-fA-F0-9]{40}" | head -1 fi - diff --git a/services/relay/README.md b/services/relay/README.md index e63609a..8ed8f8b 100644 --- a/services/relay/README.md +++ b/services/relay/README.md @@ -71,7 +71,7 @@ When **no** 138→Mainnet (or configured destination) relay deliveries are neede | `RELAY_SHEDDING_SOURCE_POLL_INTERVAL_MS` | Source router log poll interval while shedding (default **60000** ms, min 5000). Reduces Chain 138 RPC usage. | | `RELAY_SHEDDING_QUEUE_POLL_MS` | Idle interval for the queue loop while shedding (default **5000** ms, min 1000). | -**Behavior:** Source `MessageSent` logs are still ingested and messages **queue in memory**. When you set `RELAY_SHEDDING=0` (and `RELAY_DELIVERY_ENABLED=1`) and **restart** the service, pending messages are delivered as usual. For production, plan shedding around low bridge traffic so the queue stays small (in-memory queue is lost on process crash). +**Behavior:** Source `MessageSent` logs are still ingested and messages queue locally. Pending queue state is now persisted to `services/relay/data/queue-state.json` by default (override with `RELAY_QUEUE_STATE_PATH`), so a restart no longer drops queued work. For production, still plan shedding around low bridge traffic so the persisted backlog stays small and intentional. ## Skip specific message IDs @@ -90,6 +90,10 @@ RELAY_SKIP_MESSAGE_IDS=0xf718c9895c0a5442349996383184d017d2fa041af7aaeb9f0c0675d The relay checks this list during live event ingestion, historical replay, and queue processing. +For the current Mainnet WETH backlog policy, see: + +- [`docs/03-deployment/MAINNET_WETH_RELAY_BACKLOG_POLICY.md`](../../../docs/03-deployment/MAINNET_WETH_RELAY_BACKLOG_POLICY.md) + ### On-chain pause (`CCIPRelayRouter`) The destination **CCIPRelayRouter** inherits OpenZeppelin **`Pausable`**: admins with `DEFAULT_ADMIN_ROLE` may call **`pause()`** / **`unpause()`**. While paused, **`relayMessage` reverts** (no delivery through the router). diff --git a/services/relay/src/MessageQueue.js b/services/relay/src/MessageQueue.js index 43cdf21..3e9d4d4 100644 --- a/services/relay/src/MessageQueue.js +++ b/services/relay/src/MessageQueue.js @@ -2,15 +2,115 @@ * Message Queue for managing pending relay messages */ +import { mkdir, readFile, rename, writeFile } from 'fs/promises'; +import path from 'path'; + export class MessageQueue { - constructor(logger) { + constructor(logger, options = {}) { this.logger = logger; + this.persistencePath = options.persistencePath || ''; this.queue = []; this.processed = new Set(); this.failed = new Set(); this.retryCounts = new Map(); this.messageStore = new Map(); this.inFlight = new Map(); + this.lastPersistedAt = null; + this.persistenceEnabled = Boolean(this.persistencePath); + } + + async init() { + await this.loadSnapshot(); + } + + serialize() { + return { + version: 1, + queue: this.queue, + retryCounts: Object.fromEntries(this.retryCounts.entries()), + savedAt: new Date().toISOString() + }; + } + + static encodeForPersistence(value) { + if (typeof value === 'bigint') { + return { __type: 'bigint', value: value.toString() }; + } + if (Array.isArray(value)) { + return value.map((item) => MessageQueue.encodeForPersistence(item)); + } + if (value && typeof value === 'object') { + return Object.fromEntries( + Object.entries(value).map(([key, entry]) => [key, MessageQueue.encodeForPersistence(entry)]) + ); + } + return value; + } + + static decodeFromPersistence(value) { + if (Array.isArray(value)) { + return value.map((item) => MessageQueue.decodeFromPersistence(item)); + } + if (value && typeof value === 'object') { + if (value.__type === 'bigint' && typeof value.value === 'string') { + return BigInt(value.value); + } + return Object.fromEntries( + Object.entries(value).map(([key, entry]) => [key, MessageQueue.decodeFromPersistence(entry)]) + ); + } + return value; + } + + async persistSnapshot() { + if (!this.persistenceEnabled) return; + + const directory = path.dirname(this.persistencePath); + const tmpPath = `${this.persistencePath}.tmp`; + await mkdir(directory, { recursive: true }); + await writeFile( + tmpPath, + JSON.stringify(MessageQueue.encodeForPersistence(this.serialize()), null, 2) + ); + await rename(tmpPath, this.persistencePath); + this.lastPersistedAt = new Date().toISOString(); + } + + async loadSnapshot() { + if (!this.persistenceEnabled) return; + + try { + const raw = await readFile(this.persistencePath, 'utf8'); + const parsed = JSON.parse(raw); + const restoredQueueRaw = Array.isArray(parsed.queue) ? parsed.queue : []; + const restoredQueue = MessageQueue.decodeFromPersistence(restoredQueueRaw); + const restoredRetryCounts = parsed.retryCounts && typeof parsed.retryCounts === 'object' + ? Object.entries(parsed.retryCounts) + : []; + + this.queue = restoredQueue; + this.messageStore.clear(); + for (const message of restoredQueue) { + if (message?.messageId) { + this.messageStore.set(message.messageId, message); + } + } + this.retryCounts = new Map( + restoredRetryCounts.map(([messageId, count]) => [messageId, Number(count) || 0]) + ); + this.lastPersistedAt = parsed.savedAt || null; + + if (restoredQueue.length > 0) { + this.logger.info( + `Loaded ${restoredQueue.length} queued relay message(s) from ${this.persistencePath}` + ); + } + } catch (error) { + if (error?.code === 'ENOENT') { + return; + } + this.logger.warn(`Failed to load relay queue snapshot from ${this.persistencePath}`, error); + } } async add(messageData) { @@ -32,6 +132,7 @@ export class MessageQueue { this.messageStore.set(messageId, messageData); // Add to queue this.queue.push(messageData); + await this.persistSnapshot(); this.logger.info(`Added message ${messageId} to queue. Queue size: ${this.queue.length}`); } @@ -43,6 +144,7 @@ export class MessageQueue { const messageData = this.queue.shift(); if (messageData && messageData.messageId) { this.inFlight.set(messageData.messageId, messageData); + await this.persistSnapshot(); } return messageData; } @@ -52,6 +154,7 @@ export class MessageQueue { this.retryCounts.delete(messageId); this.inFlight.delete(messageId); this.messageStore.delete(messageId); + await this.persistSnapshot(); this.logger.info(`Message ${messageId} marked as processed`); } @@ -59,6 +162,7 @@ export class MessageQueue { this.failed.add(messageId); this.retryCounts.delete(messageId); this.inFlight.delete(messageId); + await this.persistSnapshot(); this.logger.error(`Message ${messageId} marked as failed`); } @@ -68,6 +172,7 @@ export class MessageQueue { async resetRetryCount(messageId) { this.retryCounts.delete(messageId); + await this.persistSnapshot(); } async retry(messageId, options = {}) { @@ -75,6 +180,7 @@ export class MessageQueue { const count = this.retryCounts.get(messageId) || 0; if (increment) { this.retryCounts.set(messageId, count + 1); + await this.persistSnapshot(); } const existingIndex = this.queue.findIndex(m => m.messageId === messageId); @@ -92,6 +198,7 @@ export class MessageQueue { this.inFlight.delete(messageId); this.queue.push(messageData); + await this.persistSnapshot(); const nextCount = increment ? count + 1 : count; this.logger.info(`Message ${messageId} requeued. Retry count: ${nextCount}. Queue size: ${this.queue.length}`); } @@ -100,7 +207,9 @@ export class MessageQueue { return { queueSize: this.queue.length, processed: this.processed.size, - failed: this.failed.size + failed: this.failed.size, + persistenceEnabled: this.persistenceEnabled, + lastPersistedAt: this.lastPersistedAt }; } } diff --git a/services/relay/src/RelayService.js b/services/relay/src/RelayService.js index 8758b51..2be7eaa 100644 --- a/services/relay/src/RelayService.js +++ b/services/relay/src/RelayService.js @@ -21,7 +21,9 @@ export class RelayService { this.destinationProvider = null; this.sourceSigner = null; this.destinationSigner = null; - this.messageQueue = new MessageQueue(this.logger); + this.messageQueue = new MessageQueue(this.logger, { + persistencePath: config.queuePersistence?.path || '' + }); // Contract instances this.sourceRouter = null; @@ -260,7 +262,9 @@ export class RelayService { queue: { size: queueStats.queueSize, processed: queueStats.processed, - failed: queueStats.failed + failed: queueStats.failed, + persistence_enabled: queueStats.persistenceEnabled, + last_persisted_at: queueStats.lastPersistedAt }, last_source_poll: this.lastSourcePoll, last_seen_message: this.lastSeenMessage, @@ -333,6 +337,7 @@ export class RelayService { this.sourceSigner = new ethers.Wallet(this.config.relayer.privateKey, this.sourceProvider); this.destinationSigner = new ethers.Wallet(this.config.relayer.privateKey, this.destinationProvider); this.relayerAddress = String(this.destinationSigner.address); + await this.messageQueue.init(); this.logger.info('Relayer address: %s', this.relayerAddress); @@ -375,6 +380,7 @@ export class RelayService { async stop() { this.logger.info('Stopping relay service...'); this.isRunning = false; + await this.messageQueue.persistSnapshot(); // Additional cleanup if needed } diff --git a/services/relay/src/config.js b/services/relay/src/config.js index dd3a1a2..12fa305 100644 --- a/services/relay/src/config.js +++ b/services/relay/src/config.js @@ -235,6 +235,12 @@ export const config = { retryDelay: process.env.RETRY_DELAY ? parseInt(process.env.RETRY_DELAY) : 5000 // 5 seconds }, + queuePersistence: { + path: + process.env.RELAY_QUEUE_STATE_PATH || + path.resolve(__dirname, '../data/queue-state.json') + }, + skipMessageIds: getSkipMessageIds() }; diff --git a/services/relay/test.js b/services/relay/test.js index 3c21902..9178843 100644 --- a/services/relay/test.js +++ b/services/relay/test.js @@ -8,7 +8,9 @@ */ import { existsSync } from 'fs'; +import { mkdtemp, rm } from 'fs/promises'; import { join, dirname } from 'path'; +import { tmpdir } from 'os'; import { fileURLToPath } from 'url'; import { ethers } from 'ethers'; import { MessageQueue } from './src/MessageQueue.js'; @@ -93,7 +95,10 @@ const rejected = relay.evaluateMessageScope({ }); assert(rejected.inScope === false, 'WETH message should be rejected by the cW worker scope'); -const queue = new MessageQueue(logger); +const tempDir = await mkdtemp(join(tmpdir(), 'relay-queue-test-')); +const queueStatePath = join(tempDir, 'queue-state.json'); +const queue = new MessageQueue(logger, { persistencePath: queueStatePath }); +await queue.init(); const queuedMessage = { messageId: '0xtest-message', sender: '0x152ed3e9912161b76bdfd368d0c84b7c31c10de7', @@ -111,5 +116,76 @@ await queue.resetRetryCount(queuedMessage.messageId); await queue.retry(queuedMessage.messageId, { increment: false }); assert((await queue.getRetryCount(queuedMessage.messageId)) === 0, 'deferred requeue should not consume retry budget'); +const persistentQueue = new MessageQueue(logger, { persistencePath: queueStatePath }); +await persistentQueue.init(); +assert( + persistentQueue.getStats().queueSize === 1, + 'persisted queue snapshot should reload queued messages after restart' +); + +const probeRelay = new RelayService({ + sourceChain: { + name: 'Chain 138', + chainId: 138, + rpcUrl: 'http://example.invalid', + routerAddress: '0x42DAb7b888Dd382bD5Adcf9E038dBF1fD03b4817', + bridgeAddress: '0x152ed3e9912161b76bdfd368d0c84b7c31c10de7', + }, + destinationChain: { + name: 'Ethereum Mainnet', + chainId: 1, + rpcUrl: 'http://example.invalid', + relayRouterAddress: '0x416564Ab73Ad5710855E98dC7bC7Bff7387285BA', + relayBridgeAddress: '0x2bF74583206A49Be07E0E8A94197C12987AbD7B5', + relayBridgeAllowlist: ['0x2bF74583206A49Be07E0E8A94197C12987AbD7B5'], + chainSelector: 5009297550715157269n, + deliveryMode: 'router', + }, + tokenMapping: {}, + sourceChainSelector: 138n, + relayer: { privateKey: '0x' + '11'.repeat(32), address: '' }, + monitoring: { + startBlock: 'latest', + pollInterval: 5000, + confirmationBlocks: 1, + finalityDelayBlocks: 2, + replayWindowBlocks: 32, + }, + retry: { maxRetries: 3, retryDelay: 1 }, + queuePersistence: { path: join(tempDir, 'probe-queue-state.json') }, + skipMessageIds: new Set(), +}, logger); +await probeRelay.messageQueue.init(); +await probeRelay.messageQueue.add({ + messageId: '0xprobe-fail', + destinationChainSelector: 5009297550715157269n, + sender: '0x152ed3e9912161b76bdfd368d0c84b7c31c10de7', + receiver: cwReceiver, + data: '0x', + tokenAmounts: [{ token: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', amount: 1n, amountType: 0 }], +}); +probeRelay.destinationRelayRouter = { paused: async () => false }; +probeRelay.destinationProvider = {}; +probeRelay.getDestinationTxOptions = async () => ({ gasLimit: 1000000n }); +probeRelay.ensureTargetBridgeInventory = async () => { + throw new Error('temporary eth_call failure'); +}; +const deferredMessage = await probeRelay.messageQueue.getNext(); +await probeRelay.relayMessage(deferredMessage); +assert( + probeRelay.lastError?.scope === 'bridge_inventory_probe', + 'inventory probe failures should be tracked under bridge_inventory_probe' +); +assert( + (await probeRelay.messageQueue.getRetryCount('0xprobe-fail')) === 0, + 'inventory probe deferrals should not consume retry budget' +); +assert( + probeRelay.messageQueue.getStats().queueSize === 1, + 'inventory probe deferrals should requeue the original message' +); + +await rm(tempDir, { recursive: true, force: true }); + console.log('OK: relay service structure valid'); process.exit(0); diff --git a/test-results/foundry.json b/test-results/foundry.json index 6beaffe..99df1ef 100644 --- a/test-results/foundry.json +++ b/test-results/foundry.json @@ -1,3 +1,3 @@ Warning: Found unknown `exclude` config for profile `default` defined in foundry.toml. Error: Encountered invalid solc version in contracts/ccip-integration/CCIPLogger.sol: No solc version exists that matches the version requirement: ^0.8.20 -Encountered invalid solc version in contracts/ccip-integration/CCIPTxReporter.sol: No solc version exists that matches the version requirement: ^0.8.20 +Encountered invalid solc version in archive/solidity/contracts/ccip-integration/CCIPTxReporter.sol: No solc version exists that matches the version requirement: ^0.8.20 diff --git a/test/flash/AaveQuotePushFlashReceiver.t.sol b/test/flash/AaveQuotePushFlashReceiver.t.sol new file mode 100644 index 0000000..fc6937c --- /dev/null +++ b/test/flash/AaveQuotePushFlashReceiver.t.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {AaveQuotePushFlashReceiver} from "../../contracts/flash/AaveQuotePushFlashReceiver.sol"; + +contract MockSweepToken is ERC20 { + constructor() ERC20("Mock Sweep Token", "MST") {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} + +contract AaveQuotePushFlashReceiverTest is Test { + AaveQuotePushFlashReceiver internal receiver; + MockSweepToken internal token; + + function setUp() public { + receiver = new AaveQuotePushFlashReceiver(address(0x1234), address(this)); + token = new MockSweepToken(); + token.mint(address(receiver), 1_000_000); + } + + function testOwnerCanSweepQuoteSurplusAndKeepReserve() public { + uint256 reserveRetained = 250_000; + + uint256 sweepable = receiver.quoteSurplusBalance(address(token), reserveRetained); + assertEq(sweepable, 750_000, "sweepable amount should exclude retained reserve"); + + receiver.sweepQuoteSurplus(address(token), address(this), reserveRetained); + + assertEq(token.balanceOf(address(receiver)), reserveRetained, "receiver should keep reserve"); + assertEq(token.balanceOf(address(this)), 750_000, "owner should receive swept surplus"); + } + + function testNonOwnerCannotSweep() public { + vm.prank(address(0xBEEF)); + vm.expectRevert(); + receiver.sweepQuoteSurplus(address(token), address(0xBEEF), 0); + } + + function testOwnerCanSweepExplicitTokenAmount() public { + receiver.sweepToken(address(token), address(0xCAFE), 123_456); + + assertEq(token.balanceOf(address(receiver)), 876_544, "receiver balance should decrease"); + assertEq(token.balanceOf(address(0xCAFE)), 123_456, "recipient should receive exact amount"); + } +} diff --git a/test/flash/AaveQuotePushFlashReceiverMainnetFork.t.sol b/test/flash/AaveQuotePushFlashReceiverMainnetFork.t.sol index ab132ed..aeae0ae 100644 --- a/test/flash/AaveQuotePushFlashReceiverMainnetFork.t.sol +++ b/test/flash/AaveQuotePushFlashReceiverMainnetFork.t.sol @@ -67,7 +67,7 @@ contract AaveQuotePushFlashReceiverMainnetForkTest is Test { return; } - receiver = new AaveQuotePushFlashReceiver(AAVE_POOL_MAINNET); + receiver = new AaveQuotePushFlashReceiver(AAVE_POOL_MAINNET, address(this)); unwinder = new AaveForkMockExternalUnwinder(IERC20(CWUSDC), IERC20(USDC), 112, 100); // PMM + unwind sizing can require materially more than 100 USDC on a live reserve snapshot. deal(USDC, address(unwinder), 50_000_000_000); // 50k USDC (6 decimals) for mock unwind payouts @@ -113,4 +113,47 @@ contract AaveQuotePushFlashReceiverMainnetForkTest is Test { assertLt(poolBaseAfter, poolBaseBefore, "pool base decreased via quote push"); assertGt(poolQuoteAfter, poolQuoteBefore, "pool quote increased via quote push"); } + + function testFork_ownerCanSweepRetainedQuoteSurplus() public skipIfNoFork { + uint256 amount = 2_964_298; + address recipient = address(0xBEEF); + + AaveQuotePushFlashReceiver.QuotePushParams memory p = AaveQuotePushFlashReceiver.QuotePushParams({ + integration: DODO_PMM_INTEGRATION_MAINNET, + pmmPool: POOL_CWUSDC_USDC, + baseToken: CWUSDC, + externalUnwinder: address(unwinder), + minOutPmm: 2_800_000, + minOutUnwind: amount + 1_483, + unwindData: bytes(""), + atomicBridge: AaveQuotePushFlashReceiver.AtomicBridgeParams({ + coordinator: address(0), + sourceChain: 0, + destinationChain: 0, + destinationAsset: address(0), + bridgeAmount: 0, + minDestinationAmount: 0, + destinationRecipient: address(0), + destinationDeadline: 0, + routeId: bytes32(0), + settlementMode: bytes32(0), + submitCommitment: false + }) + }); + + receiver.flashQuotePush(USDC, amount, p); + + uint256 retainedBeforeSweep = IERC20(USDC).balanceOf(address(receiver)); + uint256 reserveRetained = 10_000; + uint256 expectedSweep = retainedBeforeSweep - reserveRetained; + + uint256 sweepable = receiver.quoteSurplusBalance(USDC, reserveRetained); + assertEq(sweepable, expectedSweep, "sweepable balance excludes retained reserve"); + + uint256 recipientBefore = IERC20(USDC).balanceOf(recipient); + receiver.sweepQuoteSurplus(USDC, recipient, reserveRetained); + + assertEq(IERC20(USDC).balanceOf(address(receiver)), reserveRetained, "receiver keeps configured reserve"); + assertEq(IERC20(USDC).balanceOf(recipient), recipientBefore + expectedSweep, "recipient receives swept surplus"); + } } diff --git a/test/flash/QuotePushTreasuryManager.t.sol b/test/flash/QuotePushTreasuryManager.t.sol new file mode 100644 index 0000000..e364350 --- /dev/null +++ b/test/flash/QuotePushTreasuryManager.t.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {QuotePushTreasuryManager} from "../../contracts/flash/QuotePushTreasuryManager.sol"; + +contract MockTreasuryToken is ERC20 { + constructor() ERC20("Mock Treasury Token", "MTT") {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} + +contract MockSweepableReceiver is Ownable { + using SafeERC20 for IERC20; + + IERC20 internal immutable token; + + constructor(address initialOwner, IERC20 token_) Ownable(initialOwner) { + token = token_; + } + + function quoteSurplusBalance(address quoteToken, uint256 reserveRetained) external view returns (uint256 surplus) { + require(quoteToken == address(token), "wrong token"); + uint256 balance = token.balanceOf(address(this)); + if (balance > reserveRetained) { + surplus = balance - reserveRetained; + } + } + + function sweepQuoteSurplus(address quoteToken, address to, uint256 reserveRetained) + external + onlyOwner + returns (uint256 amount) + { + require(quoteToken == address(token), "wrong token"); + uint256 balance = token.balanceOf(address(this)); + require(balance > reserveRetained, "nothing to sweep"); + amount = balance - reserveRetained; + token.safeTransfer(to, amount); + } +} + +contract QuotePushTreasuryManagerTest is Test { + MockTreasuryToken internal token; + MockSweepableReceiver internal receiver; + QuotePushTreasuryManager internal manager; + + address internal constant OPERATOR = address(0xBEEF); + address internal constant GAS_RECIPIENT = address(0xCAFE); + address internal constant RECYCLE_RECIPIENT = address(0xF00D); + + function setUp() public { + token = new MockTreasuryToken(); + receiver = new MockSweepableReceiver(address(this), token); + manager = new QuotePushTreasuryManager( + address(this), address(receiver), address(token), OPERATOR, GAS_RECIPIENT, RECYCLE_RECIPIENT, 200_000, 100_000 + ); + + receiver.transferOwnership(address(manager)); + token.mint(address(receiver), 1_000_000); + } + + function testHarvestReceiverSurplusKeepsReceiverReserve() public { + assertTrue(manager.isReceiverOwnedByManager(), "manager should own receiver"); + assertEq(manager.receiverSweepableQuote(), 800_000, "sweepable quote should exclude receiver reserve"); + + uint256 harvested = manager.harvestReceiverSurplus(); + + assertEq(harvested, 800_000, "harvested amount should match receiver surplus"); + assertEq(token.balanceOf(address(receiver)), 200_000, "receiver should keep configured reserve"); + assertEq(manager.quoteBalance(), 800_000, "manager should receive harvested quote"); + assertEq(manager.availableQuote(), 700_000, "manager reserve should be retained"); + } + + function testOperatorCanDistributeConfiguredRecipients() public { + manager.harvestReceiverSurplus(); + + vm.prank(OPERATOR); + manager.distributeToConfiguredRecipients(250_000, 300_000); + + assertEq(token.balanceOf(GAS_RECIPIENT), 250_000, "gas recipient should receive configured amount"); + assertEq(token.balanceOf(RECYCLE_RECIPIENT), 300_000, "recycle recipient should receive configured amount"); + assertEq(manager.quoteBalance(), 250_000, "manager should retain the undistributed quote"); + assertEq(manager.availableQuote(), 150_000, "manager reserve should still be protected"); + } + + function testDistributeRevertsWhenRequestedAmountExceedsAvailable() public { + manager.harvestReceiverSurplus(); + + vm.prank(OPERATOR); + vm.expectRevert(); + manager.distributeToConfiguredRecipients(500_000, 250_001); + } + + function testOwnerCanRescueNonQuoteToken() public { + MockTreasuryToken other = new MockTreasuryToken(); + other.mint(address(manager), 42); + + manager.rescueToken(address(other), address(this), 42); + + assertEq(other.balanceOf(address(this)), 42, "owner should be able to rescue unrelated tokens"); + } +}