chore: sync submodule state (parent ref update)
Made-with: Cursor
This commit is contained in:
35
docs/treasury/CCIP_LIVE_CHECKLIST.md
Normal file
35
docs/treasury/CCIP_LIVE_CHECKLIST.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# CCIP Live Checklist (Chain 138 Exports)
|
||||
|
||||
Before enabling exports from Chain 138 to Ethereum Mainnet, complete the following. Until then, keep `exportsEnabled == false` on `CcipBridgeAdapter138`.
|
||||
|
||||
## 1. Chain 138 in CCIP Directory
|
||||
|
||||
- [ ] Open [Chainlink CCIP supported networks](https://docs.chain.link/ccip/supported-networks) (CCIP Directory).
|
||||
- [ ] Confirm **Chain 138** (DeFi Oracle Meta Mainnet) is listed with an official **chain selector** and **CCIP Router** address.
|
||||
- [ ] If Chain 138 is not listed, exports will not work at the network layer; do not set `exportsEnabled = true`.
|
||||
|
||||
## 2. Update CHAIN138_SELECTOR
|
||||
|
||||
- [ ] Set `CHAIN138_SELECTOR` in `.env` to the **official** decimal chain selector from the CCIP Directory (not the placeholder `138`).
|
||||
- [ ] Verify: `cast call <CCIP_ROUTER_138> "getChainSelector()(uint64)" --rpc-url $RPC_URL_138` matches your config if the router exposes it.
|
||||
|
||||
## 3. Dry-run / simulation
|
||||
|
||||
- [ ] Run a dry-run or simulation of `ccipSend` (e.g. `DRY_RUN=1` with your fund script or a minimal send that reverts before actually sending).
|
||||
- [ ] Confirm no revert from router or bridge for a small amount.
|
||||
|
||||
## 4. Enable exports on-chain
|
||||
|
||||
- [ ] Call `CcipBridgeAdapter138.setExportsEnabled(true)` (via admin/multisig).
|
||||
- [ ] Optionally process any queued intents recorded while exports were disabled.
|
||||
|
||||
## 5. WETH9 fingerprint (before first run)
|
||||
|
||||
- [ ] Run `node scripts/treasury/verify-weth9-fingerprint.js` (or `scripts/verify-weth9-canonical.js`).
|
||||
- [ ] Do not assume `0xC02a…6Cc2` on Chain 138 is canonical WETH9 until fingerprint matches expected; halt bot/executor if mismatch.
|
||||
|
||||
## References
|
||||
|
||||
- [EXECUTOR_ALLOWLIST_MATRIX.md](EXECUTOR_ALLOWLIST_MATRIX.md)
|
||||
- [EXPORT_STATE_MACHINE.md](EXPORT_STATE_MACHINE.md)
|
||||
- [Chainlink CCIP Directory](https://docs.chain.link/ccip/directory/mainnet)
|
||||
64
docs/treasury/EXECUTOR_ALLOWLIST_MATRIX.md
Normal file
64
docs/treasury/EXECUTOR_ALLOWLIST_MATRIX.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Executor Allowlist Matrix
|
||||
|
||||
**Purpose:** Single source of truth for canonical addresses and permitted call graph for the Chain 138 → Ethereum Mainnet export path. Reference this in contract NatSpec and the CCIP-live runbook.
|
||||
|
||||
---
|
||||
|
||||
## Table 1 — Canonical addresses
|
||||
|
||||
### Chain 138 canonical inputs
|
||||
|
||||
Used only by StrategyExecutor138 / TreasuryVault as allowed tokens.
|
||||
|
||||
| Symbol | Address (checksummed) |
|
||||
| ----------- | -------------------------------------------------- |
|
||||
| cUSDC_138 | `0xf22258f57794CC8E06237084b353Ab30fFfa640b` |
|
||||
| cUSDT_138 | `0x93E66202A11B1772E55407B32B44e5Cd8eda7f22` |
|
||||
| WETH9_138 | `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` |
|
||||
| WETH10_138 | `0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f` |
|
||||
|
||||
### Ethereum Mainnet canonical outputs
|
||||
|
||||
Used only by ReceiverExecutorMainnet for swaps/unwrap.
|
||||
|
||||
| Symbol | Address (checksummed) |
|
||||
| -------------- | -------------------------------------------------- |
|
||||
| WETH9_mainnet | `0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2` |
|
||||
| USDC_mainnet | `0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48` |
|
||||
| USDT_mainnet | `0xdAC17F958D2ee523a2206206994597C13D831ec7` |
|
||||
|
||||
### CCIP core
|
||||
|
||||
| Role | Chain | Address (checksummed) |
|
||||
| ----------------------- | ------- | -------------------------------------------------- |
|
||||
| CCIP Router | Mainnet | `0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D` |
|
||||
| CCIP Router | 138 | `0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e` |
|
||||
| CCIPWETH9 Bridge | 138 | `0x971cD9D156f193df8051E48043C476e53ECd4693` |
|
||||
| Ethereum Mainnet selector (decimal) | — | `5009297550715157269` |
|
||||
|
||||
---
|
||||
|
||||
## Table 2 — Permitted call graph
|
||||
|
||||
| Callee | Caller(s) | Purpose |
|
||||
| ----------------------- | ------------------------------------------------------------------------- | ------- |
|
||||
| TreasuryVault | StrategyExecutor138, CcipBridgeAdapter138, (optional LPManager) | requestTransfer / pull for harvest, rebalance, export |
|
||||
| TreasuryVault | Admin only | Config: modules, token allowlist, caps |
|
||||
| StrategyExecutor138 | Keeper / bot or multisig | harvestFees, rebalanceLp, exportToMainnet |
|
||||
| StrategyExecutor138 | Admin only | ExportPolicy, router/LP allowlist |
|
||||
| CcipBridgeAdapter138 | StrategyExecutor138 only | sendWeth9ToMainnet(amount, minAmount, deadline) |
|
||||
| ReceiverExecutorMainnet | CCIP Router (or bridge callback) | Receive CCIP transfer (WETH9) |
|
||||
| ReceiverExecutorMainnet | Keeper (optional) | swap/unwrap to USDC, USDT, ETH |
|
||||
|
||||
---
|
||||
|
||||
## Table 3 — Token flow
|
||||
|
||||
| Stage | Token(s) allowed |
|
||||
| ------------------------ | ---------------- |
|
||||
| Leave TreasuryVault | cUSDC_138, cUSDT_138, WETH9_138, WETH10_138 (canonical 138 list only) |
|
||||
| Sent via CcipBridgeAdapter138 | WETH9_138 only |
|
||||
| Received on Mainnet (ReceiverExecutorMainnet) | WETH9_mainnet only (from CCIP) |
|
||||
| Swap/unwrap on Mainnet | WETH9_mainnet, USDC_mainnet, USDT_mainnet, ETH (hardcoded addresses only) |
|
||||
|
||||
No calldata-provided token or receiver addresses for export or swap destinations.
|
||||
47
docs/treasury/EXECUTOR_BOT_INTEGRATION.md
Normal file
47
docs/treasury/EXECUTOR_BOT_INTEGRATION.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Executor Bot Integration
|
||||
|
||||
Bot triggers harvest, rebalance, export. Must not set token addresses, receiver, selector, or caps.
|
||||
|
||||
## Entrypoints (StrategyExecutor138)
|
||||
|
||||
| Function | When to call | Notes |
|
||||
| -------- | ------------ | ----- |
|
||||
| `harvestFees()` | Per strategy schedule | Stub: reverts `NotImplemented` until LP contracts are wired. |
|
||||
| `rebalanceLp()` | Per strategy schedule | Stub: reverts `NotImplemented` until LP contracts are wired. |
|
||||
| `exportToMainnet(weth9Token, weth9Amount, deadline)` | When CCIP is live and policy/caps allow | Direct export. Requires `exportsEnabled == true` on CcipBridgeAdapter138. |
|
||||
| `recordExportIntent(token, amount)` | When CCIP is **not** live | Records a single pending intent (overwrites previous). Call only when `exportsEnabled == false`. |
|
||||
| `processPendingIntent(deadline)` | After CCIP is enabled and a pending intent exists | Executes the recorded intent (same path as `exportToMainnet`) and clears the slot. |
|
||||
|
||||
## ExportPolicy (StrategyExecutor138)
|
||||
|
||||
- **Read:** `exportPolicy()` returns (mode, minExportUsd, maxPerTxUsd, maxDailyUsd, rateLimitPerHour, cooldownBlocks, exportAsset, destinationSelector, destinationReceiver).
|
||||
- **Set:** Admin calls `setExportPolicy(ExportPolicy)` (e.g. after deploy or when changing mode).
|
||||
- **Modes:** `Daily` (sweep on schedule), `Threshold` (export when balance ≥ minExportUsd), `Hybrid`.
|
||||
- Caps are enforced by TreasuryVault; the policy’s `minExportUsd` is for bot logic (when to trigger in Threshold/Hybrid mode).
|
||||
|
||||
## Intent queue (CCIP not live)
|
||||
|
||||
- While `exportsEnabled == false`, call `recordExportIntent(allowedWeth9Token, amount)` (KEEPER).
|
||||
- When CCIP is enabled, call `processPendingIntent(deadline)` (KEEPER) to execute the pending intent once.
|
||||
- Only one pending intent is stored; recording again overwrites it.
|
||||
|
||||
## Startup
|
||||
|
||||
1. Run: `node scripts/treasury/verify-weth9-fingerprint.js`
|
||||
2. Optionally set `ExportPolicy` on StrategyExecutor138 (admin) and `expectedWeth9Source` on ReceiverExecutorMainnet (admin) for operator reference.
|
||||
|
||||
## Implementation status (complete)
|
||||
|
||||
| Item | Status |
|
||||
| ---- | ------ |
|
||||
| ExportPolicy struct + setter (StrategyExecutor138) | Done |
|
||||
| Intent queue: recordExportIntent / processPendingIntent | Done |
|
||||
| harvestFees() / rebalanceLp() entrypoints (stubs) | Done |
|
||||
| Receiver expected WETH9 source (setExpectedWeth9Source / getExpectedWeth9Source) | Done |
|
||||
| Tests: TreasuryVault, CcipBridgeAdapter138, StrategyExecutor138, ReceiverExecutorMainnet | 21 tests |
|
||||
|
||||
## Refs
|
||||
|
||||
- [EXECUTOR_ALLOWLIST_MATRIX.md](EXECUTOR_ALLOWLIST_MATRIX.md)
|
||||
- [CCIP_LIVE_CHECKLIST.md](CCIP_LIVE_CHECKLIST.md)
|
||||
- [EXPORT_STATE_MACHINE.md](EXPORT_STATE_MACHINE.md)
|
||||
64
docs/treasury/EXPORT_STATE_MACHINE.md
Normal file
64
docs/treasury/EXPORT_STATE_MACHINE.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Export State Machine (exportToMainnet)
|
||||
|
||||
**Purpose:** Precise state machine for the export path from Chain 138 to Ethereum Mainnet, including failure handling and queued intents while CCIP is not live.
|
||||
|
||||
---
|
||||
|
||||
## States
|
||||
|
||||
| State | Description |
|
||||
| ------------------ | ----------- |
|
||||
| DISABLED | `exportsEnabled == false`; no CCIP send allowed. |
|
||||
| IDLE | Ready; caps OK; may accept `exportToMainnet()` call. |
|
||||
| PENDING_CAP_CHECK | Validating per-tx, daily, and hourly caps. |
|
||||
| PENDING_CCIP_SEND | Calling CCIPWETH9Bridge.sendCrossChain. |
|
||||
| QUEUED | Intent recorded; CCIP not live or simulation mode. |
|
||||
| FAILED | Revert or recorded failure; cooldown applies. |
|
||||
| COMPLETED | Export message accepted by CCIP. |
|
||||
|
||||
---
|
||||
|
||||
## Diagram
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
direction LR
|
||||
DISABLED: exportsEnabled = false
|
||||
IDLE: Ready, caps OK
|
||||
PENDING_CAP_CHECK: Check per-tx/daily/hourly
|
||||
PENDING_CCIP_SEND: Call CCIPWETH9Bridge
|
||||
QUEUED: Intent recorded, CCIP not live
|
||||
FAILED: Revert / record failure
|
||||
COMPLETED: Export sent
|
||||
|
||||
[*] --> DISABLED
|
||||
DISABLED --> IDLE: exportsEnabled = true
|
||||
IDLE --> PENDING_CAP_CHECK: exportToMainnet() called
|
||||
PENDING_CAP_CHECK --> FAILED: Caps exceeded
|
||||
PENDING_CAP_CHECK --> PENDING_CCIP_SEND: Caps OK
|
||||
PENDING_CCIP_SEND --> QUEUED: CCIP not live / simulation
|
||||
PENDING_CCIP_SEND --> FAILED: Send revert
|
||||
PENDING_CCIP_SEND --> COMPLETED: Message accepted
|
||||
QUEUED --> PENDING_CCIP_SEND: Retry when live
|
||||
FAILED --> IDLE: After cooldown / admin reset
|
||||
COMPLETED --> IDLE: Reset counters as needed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Failure handling
|
||||
|
||||
- On revert from CCIP or CCIPWETH9Bridge: transition to **FAILED**.
|
||||
- Optional persistent **intent** (amount, recipient) for retry when CCIP is live.
|
||||
- **Cooldown** (e.g. `cooldownBlocks`) before next attempt from FAILED → IDLE.
|
||||
- Admin may reset FAILED state after investigation.
|
||||
|
||||
---
|
||||
|
||||
## Queued intents
|
||||
|
||||
- While `exportsEnabled == false`, bot or executor may record "intent to export X WETH9" on-chain (e.g. single slot or small queue) or off-chain.
|
||||
- When `exportsEnabled` is set true, process queue (or sweep in next daily run).
|
||||
- **Implemented:** StrategyExecutor138 provides a single-slot intent queue:
|
||||
- `recordExportIntent(token, amount)` — callable by KEEPER when `exportsEnabled == false`; stores one pending intent (overwrites any previous).
|
||||
- `processPendingIntent(deadline)` — callable by KEEPER when `exportsEnabled == true`; executes the pending intent (same path as `exportToMainnet`) and clears the slot.
|
||||
Reference in New Issue
Block a user