Enhance .env configuration with Infura support and add new RPC endpoints for various networks. Update package.json with new deployment scripts for Engine X. Improve public LP compliance documentation in runbooks and scripts, including guidance for public pair repairs and funding strategies.
All checks were successful
Deploy to Phoenix / validate (push) Successful in 1m11s
Deploy to Phoenix / deploy (push) Successful in 43s
Deploy to Phoenix / deploy-atomic-swap-dapp (push) Successful in 1m32s
phoenix-deploy Deployed to cloudflare-sync
Deploy to Phoenix / cloudflare (push) Successful in 38s
All checks were successful
Deploy to Phoenix / validate (push) Successful in 1m11s
Deploy to Phoenix / deploy (push) Successful in 43s
Deploy to Phoenix / deploy-atomic-swap-dapp (push) Successful in 1m32s
phoenix-deploy Deployed to cloudflare-sync
Deploy to Phoenix / cloudflare (push) Successful in 38s
This commit is contained in:
@@ -113,7 +113,21 @@ PRIVATE_KEY=
|
||||
DEPLOYER_ADDRESS=
|
||||
RPC_URL_138=
|
||||
RPC_URL_138_PUBLIC=
|
||||
# Infura (recommended): one dashboard project fills JSON-RPC for Ethereum + major L2s.
|
||||
# Set INFURA_PROJECT_ID (or INFURA_API_KEY) and leave per-chain URLs empty to auto-fill in scripts/lib/load-project-env.sh,
|
||||
# or set explicit URLs: https://mainnet.infura.io/v3/<PROJECT_ID>, https://polygon-mainnet.infura.io/v3/<PROJECT_ID>, …
|
||||
INFURA_PROJECT_ID=
|
||||
INFURA_API_KEY=
|
||||
ETHEREUM_MAINNET_RPC=
|
||||
POLYGON_MAINNET_RPC=
|
||||
ARBITRUM_MAINNET_RPC=
|
||||
OPTIMISM_MAINNET_RPC=
|
||||
BASE_MAINNET_RPC=
|
||||
AVALANCHE_MAINNET_RPC=
|
||||
# BSC / Gnosis / Celo (Infura-supported networks)
|
||||
BSC_RPC_URL=
|
||||
GNOSIS_MAINNET_RPC=
|
||||
CELO_MAINNET_RPC=
|
||||
# Clear scripts/verify/check-external-dependencies.sh — use real service URLs when split; example interim health target:
|
||||
# DBIS_CORE_URL=https://dbis-api.d-bis.org/health
|
||||
DBIS_CORE_URL=
|
||||
|
||||
@@ -11,6 +11,8 @@ The final 2026-05-07 execution delivered exactly `5,000,000,000.000000 cWUSDC` t
|
||||
|
||||
The current implementation proves the Engine X internal maintained rail, not public DEX market depth. A public `cWUSDC/USDC` peg still requires separate public liquidity and quote evidence.
|
||||
|
||||
**Public LP compliance boundary:** if the proof standard requires a public, Etherscan-indexable `cWUSDC/USDC` swap against official Mainnet `USDC`, Engine X evidence alone fails that standard. The proof must use an actual public LP surface, preserve before/after reserves plus swap transaction hashes, and avoid labeling virtual internal netting as public DEX volume. See `reports/status/mainnet-cwusdc-cross-protocol-public-lp-proof-plan-20260507.md` and `reports/status/mainnet-engine-x-indexed-liquidity-upgrade-plan-20260507.md`.
|
||||
|
||||
## Proof Boundaries
|
||||
|
||||
| Claim | Status | Evidence |
|
||||
@@ -22,6 +24,7 @@ The current implementation proves the Engine X internal maintained rail, not pub
|
||||
| On-chain proof anchor | Complete for 2026-05-07 execution | `VirtualProofAuditEvidence` emitted ISO/audit/peg hashes per recipient proof |
|
||||
| Legal/regulatory approval | Not claimed | Requires external legal, compliance, AML/KYC, sanctions, and auditor evidence |
|
||||
| Public DEX peg repair | Not claimed | Requires separate public `cWUSDC/USDC` liquidity, quote, and reserve evidence |
|
||||
| Public indexed LP compliance | Blocked | Actual public LP is quote-starved; cross-protocol routes are allowed only when official-USDC unwind quotes repay all borrowed capital and fees |
|
||||
|
||||
Official ISO references used by this package:
|
||||
|
||||
@@ -35,11 +38,25 @@ Official ISO references used by this package:
|
||||
|---|---|
|
||||
| Virtual batch proof vault | `smom-dbis-138/contracts/flash/DBISEngineXVirtualBatchVault.sol` |
|
||||
| Virtual batch tests | `smom-dbis-138/test/flash/DBISEngineXVirtualBatchVault.t.sol` |
|
||||
| Indexed public LP proof vault | `smom-dbis-138/contracts/flash/DBISEngineXIndexedLiquidityVault.sol` |
|
||||
| Engine X ERC-3156 proof borrower | `smom-dbis-138/contracts/flash/DBISEngineXFlashProofBorrower.sol` |
|
||||
| XAUt-backed USDC borrow vault | `smom-dbis-138/contracts/flash/DBISEngineXXautUsdcBorrowVault.sol` |
|
||||
| XAUt-backed USDC borrow vault tests | `smom-dbis-138/test/flash/DBISEngineXXautUsdcBorrowVault.t.sol` |
|
||||
| Recipient deposit planner | `scripts/verify/plan-dbis-engine-x-recipient-deposits.py` |
|
||||
| Planner wrapper | `scripts/verify/plan-dbis-engine-x-recipient-deposits.sh` |
|
||||
| ISO/audit proof generator | `scripts/verify/generate-dbis-engine-x-iso20022-proofs.py` |
|
||||
| Proof package wrapper | `scripts/verify/build-dbis-engine-x-proof-package.sh` |
|
||||
| Canary preflight and canary hash generator | `scripts/verify/preflight-dbis-engine-x-virtual-batch-canary.py` |
|
||||
| Engine X v2 deploy dry-run | `scripts/deployment/deploy-engine-x-v2-mainnet.sh` |
|
||||
| XAUt-backed USDC borrow vault deploy dry-run | `scripts/deployment/deploy-engine-x-xaut-usdc-borrow-vault-mainnet.sh` |
|
||||
| Indexed proof vault deploy dry-run | `scripts/deployment/deploy-engine-x-indexed-liquidity-vault-mainnet.sh` |
|
||||
| Public UniV3 indexed-liquidity migration dry-run | `scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh` |
|
||||
| Legacy vault retirement dry-run | `scripts/deployment/retire-engine-x-legacy-vault.sh` |
|
||||
| Engine X small loop proof dry-run | `scripts/deployment/run-engine-x-loop-proof.sh` |
|
||||
| UniV3 public swap proof dry-run | `scripts/deployment/run-engine-x-univ3-public-swap-proof.sh` |
|
||||
| Indexed proof recorder dry-run | `scripts/deployment/record-engine-x-indexed-liquidity-proof.sh` |
|
||||
| Public indexed readiness report | `scripts/verify/check-engine-x-public-indexed-readiness.sh` |
|
||||
| Audit manifest builder | `scripts/verify/build-engine-x-audit-manifest.sh` |
|
||||
| Main status report | `reports/status/dbis-engine-x-5b-cwusdc-ladder-recalc-20260506.md` |
|
||||
| Final execution report | `reports/status/dbis-engine-x-final-recipient-proof-execution-20260507.md` |
|
||||
|
||||
@@ -136,6 +153,95 @@ Engine X proof execution must satisfy all of these conditions:
|
||||
|
||||
This proves the maintained Engine X internal accounting rail. It does not prove public market price discovery or public DEX volume.
|
||||
|
||||
## Public LP And Flash-Loan Boundary
|
||||
|
||||
Cross-protocol routing can be used for a public proof, but the roles must stay explicit:
|
||||
|
||||
- UniV2 `cWUSDC/USDC` is the public indexed proof surface.
|
||||
- UniV3 `cWUSDC/USDC` can also be used as the public indexed proof surface once created and funded with actual `cWUSDC` plus official Mainnet `USDC`.
|
||||
- Aave USDC flash liquidity is same-block working capital, not permanent LP funding.
|
||||
- The upgraded Engine X vault can provide ERC-3156 flash loans from its accounted USDC lender bucket only; it cannot lend pool USDC and it keeps flash fees in lender accounting.
|
||||
- DODO or cW mesh pools may be unwind legs only when live min-out quotes repay Aave principal plus premium in official USDC.
|
||||
- XAUt cannot currently expand Aave USDC debt capacity because live Aave XAUt LTV is `0`.
|
||||
|
||||
With current balances, the only honest public LP path is a tiny wallet-funded UniV2 canary. Larger policy-floor or listing-quality depth still needs external official Mainnet USDC.
|
||||
|
||||
## XAUt-Backed USDC Borrow Vault
|
||||
|
||||
Engine X now has a dedicated repo-side borrowing component for the banking model where `XAUt` represents XAU collateral and `USDC` represents USD debt:
|
||||
|
||||
```bash
|
||||
pnpm engine-x:borrow-vault-deploy
|
||||
```
|
||||
|
||||
The command is dry-run by default and deploys `DBISEngineXXautUsdcBorrowVault` only when `EXECUTE=1` is set. The vault:
|
||||
|
||||
- accepts `XAUt` collateral deposits;
|
||||
- lends only pre-funded official Mainnet `USDC`;
|
||||
- enforces configurable LTV, liquidation threshold, minimum health factor, liquidation bonus, and global borrow cap;
|
||||
- allows standard USDC repay, third-party USDC repay, and USDC repay with attached cWUSDC public-swap proof hashes;
|
||||
- records cWUSDC-sourced repayment proof hashes without accepting cWUSDC as debt payment;
|
||||
- exposes owner price/risk updates, pause/unpause, lender withdrawal, liquidation, and surplus-token rescue controls.
|
||||
|
||||
The borrow vault does not solve quote-side capital by itself. It is a controlled accounting surface for XAU-backed USD borrowing once the vault is funded with real USDC. If the vault has no USDC lender bucket, no borrower can draw USDC regardless of XAUt collateral value.
|
||||
|
||||
## Indexed Liquidity Upgrade Path
|
||||
|
||||
The current Engine X virtual batch vault contains a tiny balanced proof pool: `85.763529 cWUSDC / 85.763529 USDC`, plus a `5 USDC` lender bucket. That balance can be migrated into an official Mainnet Uniswap v3 `cWUSDC/USDC` position for public, indexable 1:1 proof evidence:
|
||||
|
||||
```bash
|
||||
pnpm engine-x:indexed-lp-migration
|
||||
```
|
||||
|
||||
The command is dry-run by default. It reads the live vault state, checks the official Uniswap v3 factory, simulates pool creation at exact 1:1 `sqrtPriceX96`, and prints the withdrawal, pool initialization, approval, and mint commands. It also detects whether the configured vault exposes the upgraded accounting-aware APIs.
|
||||
|
||||
The repo-side next version of `DBISEngineXVirtualBatchVault` adds:
|
||||
|
||||
- `withdrawPoolLiquidity(...)`, which decrements pool reserves and rejects withdrawals that break the maintained 1:1 pool invariant.
|
||||
- `withdrawLenderUsdc(...)`, which decrements the lender bucket.
|
||||
- ERC-3156 `maxFlashLoan`, `flashFee`, and `flashLoan`, limited to `lenderUsdcAvailable`.
|
||||
- A safer generic `withdraw(...)`, now restricted to unaccounted surplus/rescue tokens.
|
||||
- Emergency `pause()` / `unpause()` gates for proof execution, seeding, and flash loans.
|
||||
- Flash borrower allowlist controls and optional max flash amount cap.
|
||||
|
||||
The already-deployed 2026-05-07 vault does not retroactively gain those APIs. Redeploy or replace the vault before broadcasting an accounting-aware migration.
|
||||
|
||||
The indexed LP upgrade creates public proof surface only. It does not meet the `2,500 / 2,500` policy floor or the preferred `10,000 / 10,000` target without additional official Mainnet USDC.
|
||||
|
||||
**2026-05-07 live attempt:** the legacy vault balances were swept and used to create/fund the official UniV3 `cWUSDC/USDC` pool at `0x1Cf2e685682C7F7beF508F0Af15Dfb5CDda01ee3`. External swaps immediately moved the pool out of range; current active liquidity is `0` and deployer USDC is `0`. See `reports/status/engine-x-univ3-public-lp-migration-attempt-20260507.md`.
|
||||
|
||||
## Engine X V2 Public Proof Sequence
|
||||
|
||||
All commands are dry-run by default:
|
||||
|
||||
```bash
|
||||
pnpm engine-x:public-readiness
|
||||
pnpm engine-x:v2-deploy
|
||||
pnpm engine-x:borrow-vault-deploy
|
||||
pnpm engine-x:indexed-lp-migration
|
||||
pnpm engine-x:indexed-vault-deploy
|
||||
pnpm engine-x:loop-proof
|
||||
pnpm engine-x:univ3-swap-proof
|
||||
pnpm engine-x:indexed-proof-record
|
||||
pnpm engine-x:audit-manifest
|
||||
```
|
||||
|
||||
Recommended order:
|
||||
|
||||
1. Run `pnpm engine-x:public-readiness` and confirm the blockers.
|
||||
2. Deploy the upgraded accounting-aware Engine X v2 vault with `pnpm engine-x:v2-deploy`.
|
||||
3. Optionally deploy the XAUt-backed USDC borrow vault with `pnpm engine-x:borrow-vault-deploy`; fund it only with real official USDC.
|
||||
4. Seed the upgraded vault with actual `cWUSDC/USDC` and a bounded USDC lender bucket.
|
||||
5. Create/fund the official UniV3 `cWUSDC/USDC` public LP from the upgraded vault using `pnpm engine-x:indexed-lp-migration`.
|
||||
6. Deploy `DBISEngineXIndexedLiquidityVault` with `pnpm engine-x:indexed-vault-deploy`.
|
||||
7. For internal Engine X loop evidence, dry-run the exact `0.01 cWUSDC` loop proof with `pnpm engine-x:loop-proof`.
|
||||
8. Run a tiny actual UniV3 public swap proof with `pnpm engine-x:univ3-swap-proof`.
|
||||
9. Record the indexed proof with real swap/liquidity/proof hashes using `pnpm engine-x:indexed-proof-record`.
|
||||
10. Build the ABI/proof audit manifest with `pnpm engine-x:audit-manifest`.
|
||||
11. Retire the legacy vault only after v2 proof state is live and externally reviewed with `pnpm engine-x:legacy-retirement`.
|
||||
|
||||
The indexed proof vault enforces the public proof gates: nonzero public swap hash, nonzero liquidity tx hash, tick drift limit, minimum liquidity, optional pool token-balance floors, optional max proof amount, pause, and operator allowlist.
|
||||
|
||||
## Remaining External Gates
|
||||
|
||||
- Attach external compliance evidence when required by jurisdiction or counterparty policy.
|
||||
|
||||
@@ -60,7 +60,7 @@ If `eth_maxPriorityFeePerGas` is missing, the first fix path is the public node
|
||||
| **RPC_URL_138** (Core) | `http://192.168.11.211:8545` | **Prefer IP:port for admin/deploy.** Fallback from off-LAN: `https://rpc-core.d-bis.org` |
|
||||
| **RPC_URL_138_PUBLIC** (Public) | `http://192.168.11.221:8545` or `https://rpc-http-pub.d-bis.org` | Single standard for Chain 138 public; VITE_RPC_URL_138 in frontend |
|
||||
| **RPC_URL_138_FIREBLOCKS** (Fireblocks) | `http://192.168.11.232:8545` or `https://rpc-fireblocks.d-bis.org` | Dedicated RPC for Fireblocks Web3 (VMID 2301); `WS_URL_138_FIREBLOCKS`: `wss://ws.rpc-fireblocks.d-bis.org` |
|
||||
| **Ethereum Mainnet** | `https://eth.llamarpc.com` or Infura/Alchemy | `ETHEREUM_MAINNET_RPC` or `RPC_URL_MAINNET` in .env; CCIP relay uses both. Prefer Infura `https://mainnet.infura.io/v3/<PROJECT_ID>` to avoid 429. |
|
||||
| **Ethereum Mainnet** | **Prefer Infura** `https://mainnet.infura.io/v3/<PROJECT_ID>` | Set `INFURA_PROJECT_ID` (or `INFURA_API_KEY`) in `.env` to auto-fill unset `ETHEREUM_MAINNET_RPC` / L2 RPCs via `scripts/lib/load-project-env.sh`, or set `ETHEREUM_MAINNET_RPC` / `RPC_URL_MAINNET` explicitly. Avoid unauthenticated public RPCs for high-volume `cast`/indexer jobs (429 / Unauthorized). |
|
||||
| **ALL Mainnet (651940)** | `https://mainnet-rpc.alltra.global` | alltra-lifi-settlement, token-lists |
|
||||
|
||||
### Obtaining RPC URLs (Infura, Etherscan API, public RPCs)
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
| **Source to CEX production readiness** | [03-deployment/SOURCE_TO_CEX_PRODUCTION_READINESS.md](03-deployment/SOURCE_TO_CEX_PRODUCTION_READINESS.md) — repo-native readiness gate for immediate production |
|
||||
| **Immediate live production task list: source to CEX** | [03-deployment/IMMEDIATE_LIVE_PRODUCTION_TASK_LIST_SOURCE_TO_CEX.md](03-deployment/IMMEDIATE_LIVE_PRODUCTION_TASK_LIST_SOURCE_TO_CEX.md) — task list with remaining live blockers called out |
|
||||
| **ALL Mainnet protocol completion** | [03-deployment/ALL_MAINNET_PROTOCOL_COMPLETION_RUNBOOK.md](03-deployment/ALL_MAINNET_PROTOCOL_COMPLETION_RUNBOOK.md) — required inventory pools, funding/canary gates, auto-rebalancing path, and protocol enablement order for DODO, Uniswap, Balancer, Curve, Sushi, 1inch, and Aave |
|
||||
| **DBIS Engine X recipient proof package** | [03-deployment/DBIS_ENGINE_X_RECIPIENT_PROOF_RUNBOOK.md](03-deployment/DBIS_ENGINE_X_RECIPIENT_PROOF_RUNBOOK.md) — executed 2026-05-07 5B-each `cWUSDC` recipient proof path, virtual-batch vault, ISO 20022-style evidence, audit envelope, and on-chain hash-anchor flow; final report: [../reports/status/dbis-engine-x-final-recipient-proof-execution-20260507.md](../reports/status/dbis-engine-x-final-recipient-proof-execution-20260507.md) |
|
||||
| **DBIS Engine X recipient proof package** | [03-deployment/DBIS_ENGINE_X_RECIPIENT_PROOF_RUNBOOK.md](03-deployment/DBIS_ENGINE_X_RECIPIENT_PROOF_RUNBOOK.md) — executed 2026-05-07 5B-each `cWUSDC` recipient proof path, virtual-batch vault, ISO 20022-style evidence, audit envelope, and on-chain hash-anchor flow; final report: [../reports/status/dbis-engine-x-final-recipient-proof-execution-20260507.md](../reports/status/dbis-engine-x-final-recipient-proof-execution-20260507.md); public LP compliance gap/route plan: [../reports/status/mainnet-cwusdc-cross-protocol-public-lp-proof-plan-20260507.md](../reports/status/mainnet-cwusdc-cross-protocol-public-lp-proof-plan-20260507.md); indexed-liquidity upgrade plan: [../reports/status/mainnet-engine-x-indexed-liquidity-upgrade-plan-20260507.md](../reports/status/mainnet-engine-x-indexed-liquidity-upgrade-plan-20260507.md); public indexed readiness: [../reports/status/engine-x-public-indexed-readiness-latest.md](../reports/status/engine-x-public-indexed-readiness-latest.md) |
|
||||
| **External dependency blockers** | [03-deployment/EXTERNAL_DEPENDENCY_BLOCKERS.md](03-deployment/EXTERNAL_DEPENDENCY_BLOCKERS.md) — explicit list of items that cannot be closed by repo-only changes, with readiness checks and env knobs |
|
||||
| **Crypto.com OTC before vs after matrix** | [03-deployment/CRYPTO_COM_OTC_BEFORE_AFTER_OPERATOR_MATRIX.md](03-deployment/CRYPTO_COM_OTC_BEFORE_AFTER_OPERATOR_MATRIX.md) — strict operator comparison of the current ecosystem versus the state after a real Crypto.com OTC sink is connected |
|
||||
| **Provider-facing source to CEX package** | [03-deployment/PROVIDER_FACING_PACKAGE_SOURCE_TO_CEX.md](03-deployment/PROVIDER_FACING_PACKAGE_SOURCE_TO_CEX.md) — strict provider-facing package covering expectations, flow presentation, questions, and a first 30-day ramp plan |
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
- How much USDC is needed to fund one max-sized automated defense cycle
|
||||
- How far the public pair is below the current policy floor
|
||||
- Whether the current operator wallet can cover any of those gaps
|
||||
- Exact commands to fund the manager, top up the defended PMM, and reseed the public pair once inventory exists
|
||||
- Exact commands or guidance to fund the manager, top up the defended PMM, and repair the public pair once inventory exists
|
||||
|
||||
## Prereqs
|
||||
|
||||
@@ -49,6 +49,8 @@ The wrapper writes:
|
||||
- `publicLane.policyFloorQuoteShortfallUnits`
|
||||
- `holderState`
|
||||
- `holderFundingChecks`
|
||||
- `summary.publicIndexedLpComplianceStatus`
|
||||
- `summary.publicPairRepairRequiresQuoteSideAction`
|
||||
- `blockers`
|
||||
- `operatorCommands`
|
||||
|
||||
@@ -56,6 +58,8 @@ The wrapper writes:
|
||||
|
||||
- The defended-pool `1:1` number is an inference from matched 6-decimal tokens and equal reserve targets.
|
||||
- DODO PMM price can still differ from reserve ratio because the PMM curve is not a constant-product pool.
|
||||
- When the public pair is asymmetric, a plain `addLiquidity` call follows the bad reserve ratio; repair the quote side first, then add balanced liquidity.
|
||||
- Aave flash liquidity can be used only as same-block working capital unless eligible collateral or credit delegation leaves a valid debt position. It cannot be counted as durable LP funding after the flash is repaid.
|
||||
- Re-run the preflight after every liquidity move. Treat the planner as a live calculator, not a one-time document.
|
||||
|
||||
## Operator sequence once funding exists
|
||||
@@ -66,8 +70,8 @@ Use `operatorCommands.fundManagerUsdc`.
|
||||
2. Sell the planned USDC amount into the defended PMM.
|
||||
Use `operatorCommands.tradeDefendedPoolQuoteIn`.
|
||||
|
||||
3. Reseed the public pair to at least the current policy floor if public routing / discovery should be healthy again.
|
||||
Use `operatorCommands.reseedPublicPair`.
|
||||
3. Repair the public UniV2 pair if public routing / discovery should be healthy again.
|
||||
Use `operatorCommands.publicPairRepairGuidance` when only the quote side is short or the reserve-implied price is distorted. Use `operatorCommands.reseedPublicPair` only when both sides need balanced seeding and the price gate is already acceptable.
|
||||
|
||||
4. Re-run both read-only checks.
|
||||
|
||||
|
||||
12
package.json
12
package.json
@@ -60,7 +60,17 @@
|
||||
"engine-x:recipient-plan": "bash scripts/verify/plan-dbis-engine-x-recipient-deposits.sh",
|
||||
"engine-x:iso20022-proofs": "bash scripts/verify/generate-dbis-engine-x-iso20022-proofs.sh",
|
||||
"engine-x:proof-package": "bash scripts/verify/build-dbis-engine-x-proof-package.sh",
|
||||
"engine-x:canary-preflight": "bash scripts/verify/preflight-dbis-engine-x-virtual-batch-canary.sh"
|
||||
"engine-x:canary-preflight": "bash scripts/verify/preflight-dbis-engine-x-virtual-batch-canary.sh",
|
||||
"engine-x:v2-deploy": "EXECUTE=0 bash scripts/deployment/deploy-engine-x-v2-mainnet.sh",
|
||||
"engine-x:borrow-vault-deploy": "EXECUTE=0 bash scripts/deployment/deploy-engine-x-xaut-usdc-borrow-vault-mainnet.sh",
|
||||
"engine-x:indexed-vault-deploy": "EXECUTE=0 bash scripts/deployment/deploy-engine-x-indexed-liquidity-vault-mainnet.sh",
|
||||
"engine-x:indexed-lp-migration": "EXECUTE=0 bash scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh",
|
||||
"engine-x:legacy-retirement": "EXECUTE=0 bash scripts/deployment/retire-engine-x-legacy-vault.sh",
|
||||
"engine-x:loop-proof": "EXECUTE=0 bash scripts/deployment/run-engine-x-loop-proof.sh",
|
||||
"engine-x:univ3-swap-proof": "EXECUTE=0 bash scripts/deployment/run-engine-x-univ3-public-swap-proof.sh",
|
||||
"engine-x:indexed-proof-record": "EXECUTE=0 bash scripts/deployment/record-engine-x-indexed-liquidity-proof.sh",
|
||||
"engine-x:public-readiness": "bash scripts/verify/check-engine-x-public-indexed-readiness.sh",
|
||||
"engine-x:audit-manifest": "bash scripts/verify/build-engine-x-audit-manifest.sh"
|
||||
},
|
||||
"keywords": [
|
||||
"proxmox",
|
||||
|
||||
48
reports/status/engine-x-loop-proof-20260507T184556Z.json
Normal file
48
reports/status/engine-x-loop-proof-20260507T184556Z.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": false,
|
||||
"stamp": "20260507T184556Z",
|
||||
"vault": "0x9a22a3e272A364D64240dE6bda796FcA421cA7E9",
|
||||
"signer": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"recipient": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"roundingReceiver": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"loops": 1,
|
||||
"debtUsdcPerLoopRaw": "10029",
|
||||
"debtUsdcPerLoop": "0.010029",
|
||||
"exactOutputPerLoopRaw": "10000",
|
||||
"exactOutputPerLoop": "0.01",
|
||||
"proofId": "0x7c63f9a6a57ff835c5b06c2f08e51aedf9dfa202a21b1f494872834a7adb158a",
|
||||
"isoHash": "0x1f585bf5c8e1998f1442cb92472dfe4338a87ae17305196b64c35568c2c7cece",
|
||||
"auditHash": "0x2f076c1b92113a5e0357bd9b6c3b3020f4dd279962eee3d0af387c724cf3afb6",
|
||||
"pegHash": "0xcfdb6a3053d368f4a652e8ef74eeb8aac9e431cad54346d3c59fb1078636c244",
|
||||
"preview": {
|
||||
"collateralXautRaw": "4",
|
||||
"collateralXaut": "0.000004",
|
||||
"cwusdcInPerLoopRaw": "10061",
|
||||
"cwusdcInPerLoop": "0.010061",
|
||||
"cwusdcOutPerLoopRaw": "10000",
|
||||
"cwusdcOutPerLoop": "0.01",
|
||||
"cwusdcLossPerLoopRaw": "61",
|
||||
"cwusdcLossPerLoop": "0.000061",
|
||||
"totalCwusdcInRaw": "10061",
|
||||
"totalCwusdcIn": "0.010061",
|
||||
"totalCwusdcOutRaw": "10000",
|
||||
"totalCwusdcOut": "0.01",
|
||||
"exactOutputTotalRaw": "10000",
|
||||
"exactOutputTotal": "0.01",
|
||||
"outputRoundingRaw": "0",
|
||||
"outputRounding": "0",
|
||||
"totalNeutralizedRaw": "61",
|
||||
"totalNeutralized": "0.000061"
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": "56750385168300",
|
||||
"cwusdc": "56750385.1683",
|
||||
"xautRaw": "2974",
|
||||
"xaut": "0.002974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"cwusdcApproveNeeded": true,
|
||||
"xautApproveNeeded": true
|
||||
}
|
||||
}
|
||||
13
reports/status/engine-x-loop-proof-20260507T184556Z.md
Normal file
13
reports/status/engine-x-loop-proof-20260507T184556Z.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Engine X Loop Proof
|
||||
|
||||
- Executed: `False`
|
||||
- Vault: `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9`
|
||||
- Loops: `1`
|
||||
- Exact cWUSDC output per loop: `0.01`
|
||||
- Debt USDC per loop: `0.010029`
|
||||
- cWUSDC in/out per loop: `0.010061 / 0.01`
|
||||
- Neutralized per loop: `0.000061`
|
||||
- Total exact output: `0.01`
|
||||
- Proof ID: `0x7c63f9a6a57ff835c5b06c2f08e51aedf9dfa202a21b1f494872834a7adb158a`
|
||||
- cWUSDC approval needed: `True`
|
||||
- XAUt approval needed: `True`
|
||||
70
reports/status/engine-x-loop-proof-20260507T184617Z.json
Normal file
70
reports/status/engine-x-loop-proof-20260507T184617Z.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": true,
|
||||
"stamp": "20260507T184617Z",
|
||||
"vault": "0x9a22a3e272A364D64240dE6bda796FcA421cA7E9",
|
||||
"signer": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"recipient": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"roundingReceiver": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"loops": 1,
|
||||
"debtUsdcPerLoopRaw": "10029",
|
||||
"debtUsdcPerLoop": "0.010029",
|
||||
"exactOutputPerLoopRaw": "10000",
|
||||
"exactOutputPerLoop": "0.01",
|
||||
"proofId": "0x7c63f9a6a57ff835c5b06c2f08e51aedf9dfa202a21b1f494872834a7adb158a",
|
||||
"isoHash": "0x1f585bf5c8e1998f1442cb92472dfe4338a87ae17305196b64c35568c2c7cece",
|
||||
"auditHash": "0x2f076c1b92113a5e0357bd9b6c3b3020f4dd279962eee3d0af387c724cf3afb6",
|
||||
"pegHash": "0xcfdb6a3053d368f4a652e8ef74eeb8aac9e431cad54346d3c59fb1078636c244",
|
||||
"preview": {
|
||||
"collateralXautRaw": "4",
|
||||
"collateralXaut": "0.000004",
|
||||
"cwusdcInPerLoopRaw": "10061",
|
||||
"cwusdcInPerLoop": "0.010061",
|
||||
"cwusdcOutPerLoopRaw": "10000",
|
||||
"cwusdcOutPerLoop": "0.01",
|
||||
"cwusdcLossPerLoopRaw": "61",
|
||||
"cwusdcLossPerLoop": "0.000061",
|
||||
"totalCwusdcInRaw": "10061",
|
||||
"totalCwusdcIn": "0.010061",
|
||||
"totalCwusdcOutRaw": "10000",
|
||||
"totalCwusdcOut": "0.01",
|
||||
"exactOutputTotalRaw": "10000",
|
||||
"exactOutputTotal": "0.01",
|
||||
"outputRoundingRaw": "0",
|
||||
"outputRounding": "0",
|
||||
"totalNeutralizedRaw": "61",
|
||||
"totalNeutralized": "0.000061"
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": "56750385168300",
|
||||
"cwusdc": "56750385.1683",
|
||||
"xautRaw": "2974",
|
||||
"xaut": "0.002974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"cwusdcApproveNeeded": true,
|
||||
"xautApproveNeeded": true
|
||||
},
|
||||
"transactions": {
|
||||
"cwusdcApprove": "0x267338c09877188494dda5d9b7a129a541f1ef51c6300a1c5060c8e5401384e1",
|
||||
"xautApprove": "0x45a2be645ea786117f58a1413aaf6284fa9e2e3fef8ac7e3ebf2182eb21166bb",
|
||||
"runVirtualProofExactOutTo": "0xb6a69560a37e214060549dac02d1e0b31baa15ac822b4b4ed09105a4ecb713ad"
|
||||
},
|
||||
"gas": {
|
||||
"cwusdcApproveGasUsed": "45955",
|
||||
"xautApproveGasUsed": "53548",
|
||||
"runGasUsed": "142938",
|
||||
"totalGasUsed": "242441",
|
||||
"estimatedTotalCostEth": "0.000097009285243385"
|
||||
},
|
||||
"postReadback": {
|
||||
"proofUsed": true,
|
||||
"cwusdcBalanceRaw": "56750385168300",
|
||||
"xautBalanceRaw": "2974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"vaultTotalNeutralizedCwusdcRaw": "56750381619868",
|
||||
"vaultTotalVirtualLoops": "1888406152",
|
||||
"vaultTotalVirtualDebtUsdcRaw": "9442030750011029"
|
||||
}
|
||||
}
|
||||
23
reports/status/engine-x-loop-proof-20260507T184617Z.md
Normal file
23
reports/status/engine-x-loop-proof-20260507T184617Z.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Engine X Loop Proof
|
||||
|
||||
- Executed: `True`
|
||||
- Vault: `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9`
|
||||
- Loops: `1`
|
||||
- Exact cWUSDC output per loop: `0.01`
|
||||
- Debt USDC per loop: `0.010029`
|
||||
- cWUSDC in/out per loop: `0.010061 / 0.01`
|
||||
- Neutralized per loop: `0.000061`
|
||||
- Total exact output: `0.01`
|
||||
- Proof ID: `0x7c63f9a6a57ff835c5b06c2f08e51aedf9dfa202a21b1f494872834a7adb158a`
|
||||
- cWUSDC approval needed: `True`
|
||||
- XAUt approval needed: `True`
|
||||
|
||||
## Execution
|
||||
|
||||
- cWUSDC approve tx: `0x267338c09877188494dda5d9b7a129a541f1ef51c6300a1c5060c8e5401384e1`
|
||||
- XAUt approve tx: `0x45a2be645ea786117f58a1413aaf6284fa9e2e3fef8ac7e3ebf2182eb21166bb`
|
||||
- Engine X loop tx: `0xb6a69560a37e214060549dac02d1e0b31baa15ac822b4b4ed09105a4ecb713ad`
|
||||
- Total gas used: `242441`
|
||||
- Approx ETH cost: `0.000097009285243385`
|
||||
- Proof consumed on-chain: `true`
|
||||
|
||||
48
reports/status/engine-x-loop-proof-20260507T190452Z.json
Normal file
48
reports/status/engine-x-loop-proof-20260507T190452Z.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": true,
|
||||
"stamp": "20260507T190452Z",
|
||||
"vault": "0x9a22a3e272A364D64240dE6bda796FcA421cA7E9",
|
||||
"signer": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"recipient": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"roundingReceiver": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"loops": 5,
|
||||
"debtUsdcPerLoopRaw": "10029",
|
||||
"debtUsdcPerLoop": "0.010029",
|
||||
"exactOutputPerLoopRaw": "10000",
|
||||
"exactOutputPerLoop": "0.01",
|
||||
"proofId": "0x12f9dc6680b05a6ed0d08db8f5f2e654a81ea797f6f5a3cc37363fd879ccd050",
|
||||
"isoHash": "0x0e9c531dfa1b7f6037d1feac4db5819cb85416e2c223a9cd26c0a8291229798e",
|
||||
"auditHash": "0x8d94861ca42d8640fb009dab13a322f1c4d5231f7399442338538ac2018a6505",
|
||||
"pegHash": "0xccc48dd8fef23d8247bf8e9a435ce45267dc0eb2272e3a4e1a95ddcb19110d7a",
|
||||
"preview": {
|
||||
"collateralXautRaw": "4",
|
||||
"collateralXaut": "0.000004",
|
||||
"cwusdcInPerLoopRaw": "10061",
|
||||
"cwusdcInPerLoop": "0.010061",
|
||||
"cwusdcOutPerLoopRaw": "10000",
|
||||
"cwusdcOutPerLoop": "0.01",
|
||||
"cwusdcLossPerLoopRaw": "61",
|
||||
"cwusdcLossPerLoop": "0.000061",
|
||||
"totalCwusdcInRaw": "50305",
|
||||
"totalCwusdcIn": "0.050305",
|
||||
"totalCwusdcOutRaw": "50000",
|
||||
"totalCwusdcOut": "0.05",
|
||||
"exactOutputTotalRaw": "50000",
|
||||
"exactOutputTotal": "0.05",
|
||||
"outputRoundingRaw": "0",
|
||||
"outputRounding": "0",
|
||||
"totalNeutralizedRaw": "305",
|
||||
"totalNeutralized": "0.000305"
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": "56772623723927",
|
||||
"cwusdc": "56772623.723927",
|
||||
"xautRaw": "2974",
|
||||
"xaut": "0.002974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"cwusdcApproveNeeded": true,
|
||||
"xautApproveNeeded": true
|
||||
}
|
||||
}
|
||||
13
reports/status/engine-x-loop-proof-20260507T190452Z.md
Normal file
13
reports/status/engine-x-loop-proof-20260507T190452Z.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Engine X Loop Proof
|
||||
|
||||
- Executed: `True`
|
||||
- Vault: `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9`
|
||||
- Loops: `5`
|
||||
- Exact cWUSDC output per loop: `0.01`
|
||||
- Debt USDC per loop: `0.010029`
|
||||
- cWUSDC in/out per loop: `0.010061 / 0.01`
|
||||
- Neutralized per loop: `0.000061`
|
||||
- Total exact output: `0.05`
|
||||
- Proof ID: `0x12f9dc6680b05a6ed0d08db8f5f2e654a81ea797f6f5a3cc37363fd879ccd050`
|
||||
- cWUSDC approval needed: `True`
|
||||
- XAUt approval needed: `True`
|
||||
48
reports/status/engine-x-loop-proof-20260507T190621Z.json
Normal file
48
reports/status/engine-x-loop-proof-20260507T190621Z.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": true,
|
||||
"stamp": "20260507T190621Z",
|
||||
"vault": "0x9a22a3e272A364D64240dE6bda796FcA421cA7E9",
|
||||
"signer": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"recipient": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"roundingReceiver": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"loops": 1,
|
||||
"debtUsdcPerLoopRaw": "50121",
|
||||
"debtUsdcPerLoop": "0.050121",
|
||||
"exactOutputPerLoopRaw": "50000",
|
||||
"exactOutputPerLoop": "0.05",
|
||||
"proofId": "0xa0d3d62b8c59ad56b23f1455b450f90bc1bfc554113151d44825e2d17dbba0fd",
|
||||
"isoHash": "0x1c32b8a507c8a9d807b908d6896b2092d33aef0981627c9e5c76ccacfc827e37",
|
||||
"auditHash": "0x6ca4fa58e15f5439abd48feeb5f9d6739ee8e9b4a912497a3e8e64c40d7480c2",
|
||||
"pegHash": "0xb61f7a450ba2ac2314f80cb504c9b14be593ffcbe82366364fda323d7241eb16",
|
||||
"preview": {
|
||||
"collateralXautRaw": "20",
|
||||
"collateralXaut": "0.00002",
|
||||
"cwusdcInPerLoopRaw": "50302",
|
||||
"cwusdcInPerLoop": "0.050302",
|
||||
"cwusdcOutPerLoopRaw": "50000",
|
||||
"cwusdcOutPerLoop": "0.05",
|
||||
"cwusdcLossPerLoopRaw": "302",
|
||||
"cwusdcLossPerLoop": "0.000302",
|
||||
"totalCwusdcInRaw": "50302",
|
||||
"totalCwusdcIn": "0.050302",
|
||||
"totalCwusdcOutRaw": "50000",
|
||||
"totalCwusdcOut": "0.05",
|
||||
"exactOutputTotalRaw": "50000",
|
||||
"exactOutputTotal": "0.05",
|
||||
"outputRoundingRaw": "0",
|
||||
"outputRounding": "0",
|
||||
"totalNeutralizedRaw": "302",
|
||||
"totalNeutralized": "0.000302"
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": "56772623723927",
|
||||
"cwusdc": "56772623.723927",
|
||||
"xautRaw": "2974",
|
||||
"xaut": "0.002974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"cwusdcApproveNeeded": true,
|
||||
"xautApproveNeeded": true
|
||||
}
|
||||
}
|
||||
13
reports/status/engine-x-loop-proof-20260507T190621Z.md
Normal file
13
reports/status/engine-x-loop-proof-20260507T190621Z.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Engine X Loop Proof
|
||||
|
||||
- Executed: `True`
|
||||
- Vault: `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9`
|
||||
- Loops: `1`
|
||||
- Exact cWUSDC output per loop: `0.05`
|
||||
- Debt USDC per loop: `0.050121`
|
||||
- cWUSDC in/out per loop: `0.050302 / 0.05`
|
||||
- Neutralized per loop: `0.000302`
|
||||
- Total exact output: `0.05`
|
||||
- Proof ID: `0xa0d3d62b8c59ad56b23f1455b450f90bc1bfc554113151d44825e2d17dbba0fd`
|
||||
- cWUSDC approval needed: `True`
|
||||
- XAUt approval needed: `True`
|
||||
58
reports/status/engine-x-loop-proof-continuation-20260507.md
Normal file
58
reports/status/engine-x-loop-proof-continuation-20260507.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# Engine X Loop Proof Continuation - 2026-05-07
|
||||
|
||||
## Boundary
|
||||
|
||||
These are Engine X internal loop proofs against the maintained virtual batch vault. They are not public `cWUSDC/USDC` LP peg evidence and do not repair the public UniV2 pool.
|
||||
|
||||
## Vault and Signer
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Vault | `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9` |
|
||||
| Signer / recipient | `0x4A666F96fC8764181194447A7dFdb7d471b301C8` |
|
||||
| Chain | Ethereum Mainnet |
|
||||
|
||||
## Executed Proofs
|
||||
|
||||
| Proof | Loop shape | Exact output | cWUSDC input | Neutralized | Proof ID | Engine X tx |
|
||||
|---|---:|---:|---:|---:|---|---|
|
||||
| Five 0.01 loops | `5 x 0.01` | `0.05 cWUSDC` | `0.050305 cWUSDC` | `0.000305 cWUSDC` | `0x12f9dc6680b05a6ed0d08db8f5f2e654a81ea797f6f5a3cc37363fd879ccd050` | `0xcbf05070d901f3942f9fccabd23932ebf85626b5c3bb9bf58f9fac74b3a44b51` |
|
||||
| Single 0.05 loop | `1 x 0.05` | `0.05 cWUSDC` | `0.050302 cWUSDC` | `0.000302 cWUSDC` | `0xa0d3d62b8c59ad56b23f1455b450f90bc1bfc554113151d44825e2d17dbba0fd` | `0x2216cda30fc2e32aa16c5926837c20ee4aad10bcc4a047ea4911ae226866bd13` |
|
||||
|
||||
## Broadcast Hashes
|
||||
|
||||
| Proof | Step | Tx hash |
|
||||
|---|---|---|
|
||||
| `5 x 0.01` | cWUSDC approve | `0x369736f2cbb86af9079f5a3d4d744e7724f1b057bff3ede19201c8948e365aef` |
|
||||
| `5 x 0.01` | XAUt approve | `0xbc3467bc9136e875ca6bd6cc37f9e52ffdb68dd7be5907c9a124b346dd7ab3f4` |
|
||||
| `5 x 0.01` | Engine X proof | `0xcbf05070d901f3942f9fccabd23932ebf85626b5c3bb9bf58f9fac74b3a44b51` |
|
||||
| `1 x 0.05` | cWUSDC approve | `0xff61a1af904c284768c723f50cc4887c607b6c391bd6d37bfa7d708549da6b3e` |
|
||||
| `1 x 0.05` | XAUt approve | `0xa38d3f00e20de49256fec8911f657a3afc85874bfa23ea3c5129860ce3a2100b` |
|
||||
| `1 x 0.05` | Engine X proof | `0x2216cda30fc2e32aa16c5926837c20ee4aad10bcc4a047ea4911ae226866bd13` |
|
||||
|
||||
## Gas
|
||||
|
||||
| Proof | Approx ETH cost |
|
||||
|---|---:|
|
||||
| `5 x 0.01` | `0.000183577297848029 ETH` |
|
||||
| `1 x 0.05` | `0.000185301811405636 ETH` |
|
||||
| Total continuation | `~0.000368879109253665 ETH` |
|
||||
|
||||
## Final Readback
|
||||
|
||||
| Check | Value |
|
||||
|---|---|
|
||||
| `usedProofIds(0x12f9...)` | `true` |
|
||||
| `usedProofIds(0xa0d3...)` | `true` |
|
||||
| Final deployer ETH | `0.009682486338581646` |
|
||||
| Final deployer USDC | `0.118235` |
|
||||
| Final deployer cWUSDC | `56,772,623.723927` |
|
||||
| Final deployer XAUt | `0.002974` |
|
||||
| Final Engine X allowances | `0` for USDC, cWUSDC, and XAUt |
|
||||
|
||||
## Generated Artifacts
|
||||
|
||||
| Proof | JSON | Markdown |
|
||||
|---|---|---|
|
||||
| `5 x 0.01` | `reports/status/engine-x-loop-proof-20260507T190452Z.json` | `reports/status/engine-x-loop-proof-20260507T190452Z.md` |
|
||||
| `1 x 0.05` | `reports/status/engine-x-loop-proof-20260507T190621Z.json` | `reports/status/engine-x-loop-proof-20260507T190621Z.md` |
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": false,
|
||||
"stamp": "dryrun-001-20260507T190422Z",
|
||||
"vault": "0x9a22a3e272A364D64240dE6bda796FcA421cA7E9",
|
||||
"signer": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"recipient": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"roundingReceiver": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"loops": 1,
|
||||
"debtUsdcPerLoopRaw": "10029",
|
||||
"debtUsdcPerLoop": "0.010029",
|
||||
"exactOutputPerLoopRaw": "10000",
|
||||
"exactOutputPerLoop": "0.01",
|
||||
"proofId": "0xdac1d96ae02afdb616d90e9e85a313af52930d0e8eeacccf85fa25a61d4b6c49",
|
||||
"isoHash": "0x44355e38547f704597f3387514ba790e68bc5cd7db234cf6068060a4c5bd1301",
|
||||
"auditHash": "0xf1e88efbfd6007ce7357528017e279905aec4c86a04febe049eeae650112fd63",
|
||||
"pegHash": "0xf2936b13a4688a42d6d6e635b7697171bc08036d7acc109d001a5d68f78289b3",
|
||||
"preview": {
|
||||
"collateralXautRaw": "4",
|
||||
"collateralXaut": "0.000004",
|
||||
"cwusdcInPerLoopRaw": "10061",
|
||||
"cwusdcInPerLoop": "0.010061",
|
||||
"cwusdcOutPerLoopRaw": "10000",
|
||||
"cwusdcOutPerLoop": "0.01",
|
||||
"cwusdcLossPerLoopRaw": "61",
|
||||
"cwusdcLossPerLoop": "0.000061",
|
||||
"totalCwusdcInRaw": "10061",
|
||||
"totalCwusdcIn": "0.010061",
|
||||
"totalCwusdcOutRaw": "10000",
|
||||
"totalCwusdcOut": "0.01",
|
||||
"exactOutputTotalRaw": "10000",
|
||||
"exactOutputTotal": "0.01",
|
||||
"outputRoundingRaw": "0",
|
||||
"outputRounding": "0",
|
||||
"totalNeutralizedRaw": "61",
|
||||
"totalNeutralized": "0.000061"
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": "56772623723927",
|
||||
"cwusdc": "56772623.723927",
|
||||
"xautRaw": "2974",
|
||||
"xaut": "0.002974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"cwusdcApproveNeeded": true,
|
||||
"xautApproveNeeded": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Engine X Loop Proof
|
||||
|
||||
- Executed: `False`
|
||||
- Vault: `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9`
|
||||
- Loops: `1`
|
||||
- Exact cWUSDC output per loop: `0.01`
|
||||
- Debt USDC per loop: `0.010029`
|
||||
- cWUSDC in/out per loop: `0.010061 / 0.01`
|
||||
- Neutralized per loop: `0.000061`
|
||||
- Total exact output: `0.01`
|
||||
- Proof ID: `0xdac1d96ae02afdb616d90e9e85a313af52930d0e8eeacccf85fa25a61d4b6c49`
|
||||
- cWUSDC approval needed: `True`
|
||||
- XAUt approval needed: `True`
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": false,
|
||||
"stamp": "dryrun-001x5-20260507T190422Z",
|
||||
"vault": "0x9a22a3e272A364D64240dE6bda796FcA421cA7E9",
|
||||
"signer": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"recipient": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"roundingReceiver": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"loops": 5,
|
||||
"debtUsdcPerLoopRaw": "10029",
|
||||
"debtUsdcPerLoop": "0.010029",
|
||||
"exactOutputPerLoopRaw": "10000",
|
||||
"exactOutputPerLoop": "0.01",
|
||||
"proofId": "0x12f9dc6680b05a6ed0d08db8f5f2e654a81ea797f6f5a3cc37363fd879ccd050",
|
||||
"isoHash": "0x0e9c531dfa1b7f6037d1feac4db5819cb85416e2c223a9cd26c0a8291229798e",
|
||||
"auditHash": "0x8d94861ca42d8640fb009dab13a322f1c4d5231f7399442338538ac2018a6505",
|
||||
"pegHash": "0xccc48dd8fef23d8247bf8e9a435ce45267dc0eb2272e3a4e1a95ddcb19110d7a",
|
||||
"preview": {
|
||||
"collateralXautRaw": "4",
|
||||
"collateralXaut": "0.000004",
|
||||
"cwusdcInPerLoopRaw": "10061",
|
||||
"cwusdcInPerLoop": "0.010061",
|
||||
"cwusdcOutPerLoopRaw": "10000",
|
||||
"cwusdcOutPerLoop": "0.01",
|
||||
"cwusdcLossPerLoopRaw": "61",
|
||||
"cwusdcLossPerLoop": "0.000061",
|
||||
"totalCwusdcInRaw": "50305",
|
||||
"totalCwusdcIn": "0.050305",
|
||||
"totalCwusdcOutRaw": "50000",
|
||||
"totalCwusdcOut": "0.05",
|
||||
"exactOutputTotalRaw": "50000",
|
||||
"exactOutputTotal": "0.05",
|
||||
"outputRoundingRaw": "0",
|
||||
"outputRounding": "0",
|
||||
"totalNeutralizedRaw": "305",
|
||||
"totalNeutralized": "0.000305"
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": "56772623723927",
|
||||
"cwusdc": "56772623.723927",
|
||||
"xautRaw": "2974",
|
||||
"xaut": "0.002974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"cwusdcApproveNeeded": true,
|
||||
"xautApproveNeeded": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Engine X Loop Proof
|
||||
|
||||
- Executed: `False`
|
||||
- Vault: `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9`
|
||||
- Loops: `5`
|
||||
- Exact cWUSDC output per loop: `0.01`
|
||||
- Debt USDC per loop: `0.010029`
|
||||
- cWUSDC in/out per loop: `0.010061 / 0.01`
|
||||
- Neutralized per loop: `0.000061`
|
||||
- Total exact output: `0.05`
|
||||
- Proof ID: `0x12f9dc6680b05a6ed0d08db8f5f2e654a81ea797f6f5a3cc37363fd879ccd050`
|
||||
- cWUSDC approval needed: `True`
|
||||
- XAUt approval needed: `True`
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": false,
|
||||
"stamp": "dryrun-005-20260507T190422Z",
|
||||
"vault": "0x9a22a3e272A364D64240dE6bda796FcA421cA7E9",
|
||||
"signer": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"recipient": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"roundingReceiver": "0x4A666F96fC8764181194447A7dFdb7d471b301C8",
|
||||
"loops": 1,
|
||||
"debtUsdcPerLoopRaw": "50121",
|
||||
"debtUsdcPerLoop": "0.050121",
|
||||
"exactOutputPerLoopRaw": "50000",
|
||||
"exactOutputPerLoop": "0.05",
|
||||
"proofId": "0xa0d3d62b8c59ad56b23f1455b450f90bc1bfc554113151d44825e2d17dbba0fd",
|
||||
"isoHash": "0x1c32b8a507c8a9d807b908d6896b2092d33aef0981627c9e5c76ccacfc827e37",
|
||||
"auditHash": "0x6ca4fa58e15f5439abd48feeb5f9d6739ee8e9b4a912497a3e8e64c40d7480c2",
|
||||
"pegHash": "0xb61f7a450ba2ac2314f80cb504c9b14be593ffcbe82366364fda323d7241eb16",
|
||||
"preview": {
|
||||
"collateralXautRaw": "20",
|
||||
"collateralXaut": "0.00002",
|
||||
"cwusdcInPerLoopRaw": "50302",
|
||||
"cwusdcInPerLoop": "0.050302",
|
||||
"cwusdcOutPerLoopRaw": "50000",
|
||||
"cwusdcOutPerLoop": "0.05",
|
||||
"cwusdcLossPerLoopRaw": "302",
|
||||
"cwusdcLossPerLoop": "0.000302",
|
||||
"totalCwusdcInRaw": "50302",
|
||||
"totalCwusdcIn": "0.050302",
|
||||
"totalCwusdcOutRaw": "50000",
|
||||
"totalCwusdcOut": "0.05",
|
||||
"exactOutputTotalRaw": "50000",
|
||||
"exactOutputTotal": "0.05",
|
||||
"outputRoundingRaw": "0",
|
||||
"outputRounding": "0",
|
||||
"totalNeutralizedRaw": "302",
|
||||
"totalNeutralized": "0.000302"
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": "56772623723927",
|
||||
"cwusdc": "56772623.723927",
|
||||
"xautRaw": "2974",
|
||||
"xaut": "0.002974",
|
||||
"cwusdcAllowanceRaw": "0",
|
||||
"xautAllowanceRaw": "0",
|
||||
"cwusdcApproveNeeded": true,
|
||||
"xautApproveNeeded": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Engine X Loop Proof
|
||||
|
||||
- Executed: `False`
|
||||
- Vault: `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9`
|
||||
- Loops: `1`
|
||||
- Exact cWUSDC output per loop: `0.05`
|
||||
- Debt USDC per loop: `0.050121`
|
||||
- cWUSDC in/out per loop: `0.050302 / 0.05`
|
||||
- Neutralized per loop: `0.000302`
|
||||
- Total exact output: `0.05`
|
||||
- Proof ID: `0xa0d3d62b8c59ad56b23f1455b450f90bc1bfc554113151d44825e2d17dbba0fd`
|
||||
- cWUSDC approval needed: `True`
|
||||
- XAUt approval needed: `True`
|
||||
@@ -0,0 +1,57 @@
|
||||
# Engine X UniV3 Public LP Migration Attempt - 2026-05-07
|
||||
|
||||
## Summary
|
||||
|
||||
The legacy Engine X virtual proof vault was retired and its token balances were swept back to the deployer. A new official Uniswap v3 `cWUSDC/USDC` pool was created and funded with the maximum available official Mainnet USDC from the deployer wallet.
|
||||
|
||||
The public pool was then immediately traded by external actors. Current pool state is out of the intended active range and has no active liquidity, so it is not proof-ready for Engine X indexed-liquidity evidence.
|
||||
|
||||
## Addresses
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Legacy Engine X vault | `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9` |
|
||||
| Deployer | `0x4A666F96fC8764181194447A7dFdb7d471b301C8` |
|
||||
| UniV3 cWUSDC/USDC pool | `0x1Cf2e685682C7F7beF508F0Af15Dfb5CDda01ee3` |
|
||||
| UniV3 NFT position ID | `1278424` |
|
||||
|
||||
## Operator Transactions
|
||||
|
||||
| Step | Tx hash |
|
||||
|---|---|
|
||||
| Withdraw legacy vault USDC | `0x233a2a79cf697dae2c1d608a3a584866a1e1643646f427e434a63677ddf27c9f` |
|
||||
| Withdraw legacy vault cWUSDC | `0x7a8476a919c5d99394d0d1c14ef09c7d78b41beb9f1951ad13bf021053250f33` |
|
||||
| Create and initialize UniV3 pool | `0xa2a35393de4b5e3765922ca737beff31b7435182fc22f7be7481ba83f120abf7` |
|
||||
| Approve cWUSDC to position manager | `0xb3d720df02c02ead9f6b28239693f7253b2cdfe4ef552c95e61358a1763bbe52` |
|
||||
| Approve USDC to position manager | `0x99319d08ed90e3dc67f39bfdaf3ff99a02584a08086a7dbbc261940a2b518c5f` |
|
||||
| Mint UniV3 LP position | `0x056a8f2e97c30dd457cfcdfb428dcad301a7a47efe315717c226c12cba834e73` |
|
||||
|
||||
## LP Mint
|
||||
|
||||
| Field | Value |
|
||||
|---|---:|
|
||||
| cWUSDC deposited | `90.881764` |
|
||||
| USDC deposited | `90.881764` |
|
||||
| Tick range | `[-100, 100]` |
|
||||
| Minted liquidity | `18,222,740,349` |
|
||||
|
||||
## External Pool Activity After Mint
|
||||
|
||||
| External tx | Observation |
|
||||
|---|---|
|
||||
| `0x5e12c485b6b67a3c9f0fd0a71d478789eb92fe82f0f901bbb56bde42bc7e4a52` | External swap against the new pool immediately after LP mint |
|
||||
| `0x04a7d54fac3fd8d3a484d78aa46a7ddc43ed75f86e2c43cc04f905358152b397` | Follow-on external swap moved the pool just outside the minted range |
|
||||
|
||||
## Current Readback
|
||||
|
||||
| Check | Value |
|
||||
|---|---:|
|
||||
| Pool cWUSDC balance | `182.280270` |
|
||||
| Pool USDC balance | `0.000001` |
|
||||
| Current tick | `-101` |
|
||||
| Active liquidity | `0` |
|
||||
| Deployer USDC | `0` |
|
||||
|
||||
## Conclusion
|
||||
|
||||
This created an indexable public UniV3 pool and an NFT LP position, but it does not currently satisfy Engine X public indexed proof readiness. The pool needs additional official Mainnet USDC and protected/private execution before another public proof attempt.
|
||||
@@ -0,0 +1,129 @@
|
||||
# Mainnet cWUSDC Cross-Protocol Public LP Proof Plan
|
||||
|
||||
Date: `2026-05-07`
|
||||
|
||||
## Finding
|
||||
|
||||
The compliance-critical proof surface must use the actual public, Etherscan-indexable `cWUSDC/USDC` LP and actual official Mainnet USDC. Engine X internal accounting, cW mesh transfers, and virtual pool reserves do not satisfy that public LP swap standard by themselves.
|
||||
|
||||
Current public UniV2 discovery LP:
|
||||
|
||||
| Item | Value |
|
||||
|---|---|
|
||||
| Pair | `0xC28706F899266b36BC43cc072b3a921BDf2C48D9` |
|
||||
| Base | `cWUSDC` |
|
||||
| Quote | official Mainnet `USDC` |
|
||||
| Latest read | `2026-05-07T15:37:56Z` |
|
||||
| Reserves | `2,492,891.981995 cWUSDC / 0.000002 USDC` |
|
||||
| Status | `blocked_missing_quote_side_public_lp_evidence` |
|
||||
|
||||
Current deployer resources:
|
||||
|
||||
| Asset | Balance |
|
||||
|---|---:|
|
||||
| ETH | `0.011028088441237817` |
|
||||
| WETH | `0.000200000000000000` |
|
||||
| USDC | `2.364477` |
|
||||
| cWUSDC | `56,750,385.166450` |
|
||||
| XAUt | `0.002974` |
|
||||
| cWXAUT | `0` |
|
||||
|
||||
## Cross-Protocol Interpretation
|
||||
|
||||
Cross-protocol routing is allowed, but each protocol has a different proof role:
|
||||
|
||||
| Protocol / surface | Valid role | Current limit |
|
||||
|---|---|---|
|
||||
| UniV2 `cWUSDC/USDC` | Public indexed swap and reserve proof | Quote side is almost empty |
|
||||
| Aave USDC flash loan | Same-block working capital | Must be repaid in the same transaction unless eligible collateral/credit delegation exists |
|
||||
| Aave XAUt collateral | Informational only for debt expansion | XAUt LTV is `0`; cannot originate USDC debt against XAUt today |
|
||||
| DODO `cWUSDC/USDC` / `cWUSDT/USDC` | Possible unwind or secondary quote proof | Official-USDC quote reserves are too small for meaningful flash repayment |
|
||||
| UniV2 `cWUSDT/cWUSDC` mesh | Deep internal cW route | Does not itself create official USDC |
|
||||
|
||||
Aave current read:
|
||||
|
||||
| Field | Value |
|
||||
|---|---:|
|
||||
| Aave USDC available liquidity | `147,083,645.099602 USDC` |
|
||||
| Flash premium config | `5` bps |
|
||||
| XAUt LTV | `0` |
|
||||
| XAUt borrowing enabled | `false` |
|
||||
|
||||
## What Can Be Done Now
|
||||
|
||||
With the current wallet USDC, the smallest honest public proof is a tiny real UniV2 repair canary:
|
||||
|
||||
```text
|
||||
Swap about 2.236241794737 USDC into the actual cWUSDC/USDC UniV2 pair.
|
||||
Expected output: about 2,492,889.745751 cWUSDC.
|
||||
Post-swap reserves: about 2.236243794737 cWUSDC / 2.236243794737 USDC.
|
||||
Then add the remaining about 0.128235205263 USDC plus matching cWUSDC as balanced liquidity.
|
||||
Final wallet-only public LP depth: about 2.364479 / 2.364479.
|
||||
```
|
||||
|
||||
The dry-run canary script keeps `0.01 USDC` back by default, so its default broadcast plan is slightly smaller:
|
||||
|
||||
```text
|
||||
Default balanced add after repair: 0.118235 USDC plus matching cWUSDC.
|
||||
Default final public LP depth: about 2.354479 / 2.354479.
|
||||
Override MAINNET_PUBLIC_LP_USDC_KEEP_RAW only after reviewing gas and reserve needs.
|
||||
```
|
||||
|
||||
This would create real public LP swap evidence and actual USDC-backed reserves, but it is not enough for the `2,500 / 2,500` policy floor and not enough for the preferred `10,000 / 10,000` evidence target.
|
||||
|
||||
Remaining USDC gap after current wallet balance:
|
||||
|
||||
| Target | Additional official USDC needed after current wallet |
|
||||
|---|---:|
|
||||
| Policy floor `2,500 / 2,500` | `2,497.635521 USDC` |
|
||||
| Preferred `10,000 / 10,000` | `9,997.635521 USDC` |
|
||||
| Defended DODO parity | at least `290,993.364737 USDC` by current planner |
|
||||
|
||||
## Aave Flash Loan Use
|
||||
|
||||
Aave can be used as an execution component, but not as free permanent liquidity.
|
||||
|
||||
Valid Aave proof shape:
|
||||
|
||||
```text
|
||||
Aave flash USDC
|
||||
Use USDC in actual public UniV2 cWUSDC/USDC swap
|
||||
Unwind acquired cWUSDC across approved routes into official USDC
|
||||
Repay Aave principal + fee in the same transaction
|
||||
Emit/save proof events and reserve readbacks
|
||||
```
|
||||
|
||||
Current blocker:
|
||||
|
||||
```text
|
||||
official-USDC unwind capacity < Aave principal + fee
|
||||
```
|
||||
|
||||
The cW mesh has deep `cWUSDC/cWUSDT` liquidity, but the official USDC exits are tiny. A flash loan sized for `2,500 USDC` would require at least `2,501.25 USDC` repayment at a `5` bps premium; current official-USDC exit liquidity is nowhere near that.
|
||||
|
||||
A tiny Aave-assisted canary is possible only if the deployer repays the flash from its own USDC. That proves Aave + UniV2 routing, but it does not expand durable LP capacity and costs extra premium versus using the wallet USDC directly.
|
||||
|
||||
## Recommended Execution Order
|
||||
|
||||
1. Keep the Engine X recipient proof separate from public LP compliance language.
|
||||
2. Dry-run the wallet-only UniV2 quote-side repair canary against the actual pair.
|
||||
3. If the canary is acceptable, execute only the tiny public proof and capture:
|
||||
- swap tx,
|
||||
- add-liquidity tx,
|
||||
- reserves before and after,
|
||||
- token transfers,
|
||||
- planner JSON,
|
||||
- Etherscan links.
|
||||
4. Do not run a meaningful Aave flash-loan proof until an official-USDC unwind route can repay principal plus premium from on-chain quotes.
|
||||
5. For policy-floor or listing-quality compliance, fund official Mainnet USDC first, then run quote-side repair followed by balanced LP.
|
||||
|
||||
## Safe Commands
|
||||
|
||||
```bash
|
||||
bash scripts/verify/snapshot-mainnet-cwusdc-usdc-preflight.sh
|
||||
bash scripts/verify/plan-mainnet-cwusdc-usdc-repeg.sh
|
||||
jq '.summary, .holderFundingChecks, .recommendedActions' reports/status/mainnet-cwusdc-usdc-repeg-plan-latest.json
|
||||
EXECUTE=0 bash scripts/deployment/repair-mainnet-cwusdc-usdc-univ2-canary.sh
|
||||
```
|
||||
|
||||
The canary script is dry-run by default. Do not set `EXECUTE=1` until the quote, minimum output, gas, and compliance intent are explicitly reviewed.
|
||||
@@ -0,0 +1,151 @@
|
||||
# Mainnet Engine X Indexed Liquidity Upgrade Plan
|
||||
|
||||
Date: `2026-05-07`
|
||||
|
||||
## Goal
|
||||
|
||||
Upgrade the Engine X proof surface from an internal virtual `cWUSDC ~= USDC` accounting rail to public, Etherscan-indexable liquidity and real `cWUSDC/USDC` swap evidence.
|
||||
|
||||
This report does not claim the current wallet can fund listing-quality depth. It defines the safe migration path for the existing small Engine X proof vault and the remaining capital gates.
|
||||
|
||||
## Current Engine X Vault State
|
||||
|
||||
| Item | Value |
|
||||
|---|---|
|
||||
| Engine X vault | `0x9a22a3e272A364D64240dE6bda796FcA421cA7E9` |
|
||||
| Vault owner | `0x4A666F96fC8764181194447A7dFdb7d471b301C8` |
|
||||
| Accounted pool reserves | `85.763529 cWUSDC / 85.763529 USDC` |
|
||||
| Lender bucket | `5.000000 USDC` |
|
||||
| Actual vault balances | `85.763529 cWUSDC / 90.763529 USDC` |
|
||||
| Public UniV3 `cWUSDC/USDC` fee `100` pool | not yet deployed |
|
||||
| Simulated UniV3 pool address | `0x1Cf2e685682C7F7beF508F0Af15Dfb5CDda01ee3` |
|
||||
|
||||
## Upgrade Model
|
||||
|
||||
Engine X public proof mode should use these public artifacts:
|
||||
|
||||
| Proof artifact | Required source |
|
||||
|---|---|
|
||||
| Public 1:1 liquidity | UniV3 `cWUSDC/USDC` position around tick `0` |
|
||||
| Public peg readback | UniV3 pool `slot0`, tick, liquidity, token balances |
|
||||
| Public swap proof | UniV3 or UniV2 transaction where actual official Mainnet `USDC` swaps against actual `cWUSDC` |
|
||||
| Engine X proof linkage | Engine X proof ID and audit hash referencing the public LP pool, position token ID, and swap tx hashes |
|
||||
|
||||
The live deployed `DBISEngineXVirtualBatchVault` at `0x9a22...A7E9` only has a generic `withdraw(...)`, which transfers tokens but does not reduce `poolCwusdcReserve`, `poolUsdcReserve`, or `lenderUsdcAvailable`. The repo-side next version now adds accounting-aware withdrawals and an ERC-3156 flash-lender interface, but the live vault must be redeployed or replaced before those APIs can be used on-chain.
|
||||
|
||||
## Repo-Side Contract Upgrade
|
||||
|
||||
Updated contract:
|
||||
|
||||
```text
|
||||
smom-dbis-138/contracts/flash/DBISEngineXVirtualBatchVault.sol
|
||||
```
|
||||
|
||||
New accounting-aware operations:
|
||||
|
||||
| Function | Purpose |
|
||||
|---|---|
|
||||
| `withdrawPoolLiquidity(address,uint256,uint256)` | Withdraws pool `cWUSDC/USDC` and decrements `poolCwusdcReserve` / `poolUsdcReserve`; rejects withdrawals that would break the maintained 1:1 pool invariant. |
|
||||
| `withdrawLenderUsdc(address,uint256)` | Withdraws from the USDC lender bucket and decrements `lenderUsdcAvailable`. |
|
||||
| `withdraw(address,address,uint256)` | Retained only for unaccounted surplus/rescue; reverts if the withdrawal would leave accounted pool/lender balances undercollateralized. |
|
||||
| `maxFlashLoan(address)` / `flashFee(address,uint256)` / `flashLoan(...)` | ERC-3156 flash-loan surface for the accounted USDC lender bucket only. |
|
||||
| `setFlashFeeBps(uint256)` | Owner-set flash fee, capped at `1,000` bps. Default is `5` bps. |
|
||||
| `pause()` / `unpause()` | Emergency gates for seeding, proof execution, and flash loans. |
|
||||
| `setFlashBorrowerAllowlistEnabled(bool)` / `setFlashBorrowerApproved(address,bool)` | Optional borrower allowlist for flash-loan callbacks. |
|
||||
| `setMaxFlashLoanAmount(uint256)` | Optional cap below the full lender bucket. |
|
||||
|
||||
Flash-loan accounting rule:
|
||||
|
||||
```text
|
||||
maxFlashLoan(USDC) = lenderUsdcAvailable
|
||||
flash repayment = principal + fee
|
||||
lenderUsdcAvailable after repayment = prior lenderUsdcAvailable + fee
|
||||
poolUsdcReserve is never lent
|
||||
```
|
||||
|
||||
This gives Engine X an internal same-transaction USDC working-capital primitive without pretending Aave flash liquidity is durable LP funding.
|
||||
|
||||
Additional public-proof contracts:
|
||||
|
||||
| Contract | Purpose |
|
||||
|---|---|
|
||||
| `DBISEngineXIndexedLiquidityVault` | Anchors Engine X proof IDs to public UniV3 pool state, swap tx hash, liquidity tx hash, and ISO/audit/peg hashes. |
|
||||
| `DBISEngineXFlashProofBorrower` | Minimal ERC-3156 borrower for proving Engine X same-transaction USDC working capital from the v2 lender bucket. |
|
||||
|
||||
## Dry-Run Operator Path
|
||||
|
||||
The new default dry-run command is:
|
||||
|
||||
```bash
|
||||
pnpm engine-x:indexed-lp-migration
|
||||
```
|
||||
|
||||
Equivalent direct command:
|
||||
|
||||
```bash
|
||||
EXECUTE=0 bash scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh
|
||||
```
|
||||
|
||||
The script:
|
||||
|
||||
1. Reads the Engine X vault owner, accounted reserves, lender bucket, and actual token balances.
|
||||
2. Finds the official Uniswap v3 `cWUSDC/USDC` pool for fee `100`.
|
||||
3. Simulates `createAndInitializePoolIfNecessary(...)` at exact 1:1 raw price.
|
||||
4. Sizes the migration to the balanced pool amount only: `85.763529 cWUSDC + 85.763529 USDC`.
|
||||
5. Checks whether the configured vault exposes the new accounting-aware APIs.
|
||||
6. Prints the exact `withdrawPoolLiquidity`, `createAndInitializePoolIfNecessary`, `approve`, and `mint` commands only when the configured vault supports the upgraded API.
|
||||
7. Leaves `EXECUTE=0` unless the operator explicitly opts into broadcast.
|
||||
|
||||
Full dry-run lifecycle:
|
||||
|
||||
```bash
|
||||
pnpm engine-x:public-readiness
|
||||
pnpm engine-x:v2-deploy
|
||||
pnpm engine-x:indexed-lp-migration
|
||||
pnpm engine-x:indexed-vault-deploy
|
||||
pnpm engine-x:univ3-swap-proof
|
||||
pnpm engine-x:indexed-proof-record
|
||||
pnpm engine-x:audit-manifest
|
||||
pnpm engine-x:legacy-retirement
|
||||
```
|
||||
|
||||
Default UniV3 parameters:
|
||||
|
||||
| Parameter | Value |
|
||||
|---|---|
|
||||
| Fee tier | `100` |
|
||||
| Tick spacing | `1` |
|
||||
| Tick lower / upper | `-100 / 100` |
|
||||
| Initial `sqrtPriceX96` | `79228162514264337593543950336` |
|
||||
| Migration amount | `85763529` raw per side |
|
||||
|
||||
## Compliance Interpretation
|
||||
|
||||
This upgrade creates a public, indexable proof surface, but only at tiny depth:
|
||||
|
||||
- It can prove actual public LP creation and actual 1:1 USDC/cWUSDC liquidity.
|
||||
- It can support tiny real swaps for on-chain proof hashes and Etherscan-visible transfer/event evidence.
|
||||
- It does not satisfy the public policy floor of `2,500 / 2,500`.
|
||||
- It does not satisfy the preferred evidence target of `10,000 / 10,000`.
|
||||
- It does not solve the existing UniV2 quote-starvation by itself.
|
||||
|
||||
## Remaining Gates
|
||||
|
||||
| Gate | Status |
|
||||
|---|---|
|
||||
| Real official Mainnet USDC in the public proof transaction | available only at tiny depth |
|
||||
| Public indexable LP | can be created with the new dry-run path |
|
||||
| Public 1:1 swap evidence | possible after the V3 LP exists, sized below available depth |
|
||||
| Policy-floor liquidity | blocked by official USDC shortfall |
|
||||
| Listing-quality `10,000 / 10,000` depth | blocked by official USDC shortfall |
|
||||
| Old live Engine X vault accounting | must be redeployed/replaced before accounting-aware migration |
|
||||
|
||||
## Recommended Next Build
|
||||
|
||||
The next contract-level upgrade should be a new Engine X indexed-liquidity adapter that:
|
||||
|
||||
- references a public UniV3 pool as the peg source of truth,
|
||||
- stores the fee tier, tick range, and position token ID,
|
||||
- requires pre/post `slot0` and liquidity checks around proof execution,
|
||||
- emits proof events containing public swap tx references and ISO/audit/peg hashes,
|
||||
- refuses to label virtual internal netting as public DEX volume.
|
||||
@@ -40,26 +40,26 @@ DEFAULT_ENV = ROOT / "smom-dbis-138" / ".env"
|
||||
|
||||
ZERO = "0x0000000000000000000000000000000000000000"
|
||||
|
||||
# Defaults when .env has no RPC for a chain (prefer setting INFURA_PROJECT_ID + load-project-env, or per-chain *_RPC in .env).
|
||||
DEFAULT_RPC: dict[str, str] = {
|
||||
"1": "https://eth.llamarpc.com",
|
||||
"1": "https://ethereum.publicnode.com",
|
||||
"10": "https://mainnet.optimism.io",
|
||||
"25": "https://evm.cronos.org",
|
||||
"56": "https://bsc-dataseed.binance.org",
|
||||
"100": "https://rpc.gnosischain.com",
|
||||
"137": "https://polygon-rpc.com",
|
||||
"8453": "https://mainnet.base.org",
|
||||
"42161": "https://arbitrum-one.publicnode.com",
|
||||
"42161": "https://arb1.arbitrum.io/rpc",
|
||||
"42220": "https://forno.celo.org",
|
||||
"43114": "https://avalanche-c-chain.publicnode.com",
|
||||
"43114": "https://api.avax.network/ext/bc/C/rpc",
|
||||
"1111": "https://api.wemix.com",
|
||||
}
|
||||
|
||||
# Extra public RPCs (retry when primary fails — connection resets, rate limits).
|
||||
RPC_FALLBACKS: dict[str, list[str]] = {
|
||||
"1": [
|
||||
"https://ethereum.publicnode.com",
|
||||
"https://eth.llamarpc.com",
|
||||
"https://1rpc.io/eth",
|
||||
"https://rpc.ankr.com/eth",
|
||||
],
|
||||
"137": ["https://polygon-bor.publicnode.com", "https://1rpc.io/matic"],
|
||||
"42161": ["https://arbitrum.llamarpc.com"],
|
||||
@@ -85,6 +85,58 @@ RPC_KEYS: dict[str, list[str]] = {
|
||||
}
|
||||
|
||||
|
||||
def _rpc_env_key_set() -> set[str]:
|
||||
return {k for ks in RPC_KEYS.values() for k in ks} | {
|
||||
"INFURA_PROJECT_ID",
|
||||
"INFURA_API_KEY",
|
||||
"RPC_URL_MAINNET",
|
||||
}
|
||||
|
||||
|
||||
def merge_rpc_os_into(env: dict[str, str]) -> None:
|
||||
"""Process env overrides .env for RPC-related keys (so `source load-project-env.sh` applies)."""
|
||||
for k in _rpc_env_key_set():
|
||||
v = os.environ.get(k, "").strip()
|
||||
if v:
|
||||
env[k] = v
|
||||
|
||||
|
||||
def apply_eth_mainnet_rpc_alias(env: dict[str, str]) -> None:
|
||||
"""Match load-project-env.sh: dotenv often sets ETH_MAINNET_RPC_URL only."""
|
||||
if not resolve(env, "ETHEREUM_MAINNET_RPC"):
|
||||
alt = resolve(env, "ETH_MAINNET_RPC_URL", "")
|
||||
if alt:
|
||||
env["ETHEREUM_MAINNET_RPC"] = alt
|
||||
|
||||
|
||||
def apply_infura_rpc_defaults(env: dict[str, str]) -> None:
|
||||
"""When INFURA_PROJECT_ID or INFURA_API_KEY is set, fill first unset RPC var per supported chain."""
|
||||
pid = (env.get("INFURA_PROJECT_ID") or env.get("INFURA_API_KEY") or "").strip()
|
||||
if not pid:
|
||||
return
|
||||
|
||||
def chain_has_rpc(cid: str) -> bool:
|
||||
return any(resolve(env, k) for k in RPC_KEYS.get(cid, []))
|
||||
|
||||
infura_by_chain: dict[str, str] = {
|
||||
"1": f"https://mainnet.infura.io/v3/{pid}",
|
||||
"10": f"https://optimism-mainnet.infura.io/v3/{pid}",
|
||||
"56": f"https://bnb-mainnet.infura.io/v3/{pid}",
|
||||
"100": f"https://gnosis-mainnet.infura.io/v3/{pid}",
|
||||
"137": f"https://polygon-mainnet.infura.io/v3/{pid}",
|
||||
"8453": f"https://base-mainnet.infura.io/v3/{pid}",
|
||||
"42161": f"https://arbitrum-mainnet.infura.io/v3/{pid}",
|
||||
"42220": f"https://celo-mainnet.infura.io/v3/{pid}",
|
||||
"43114": f"https://avalanche-mainnet.infura.io/v3/{pid}",
|
||||
}
|
||||
for cid, url in infura_by_chain.items():
|
||||
if chain_has_rpc(cid):
|
||||
continue
|
||||
keys = RPC_KEYS.get(cid, [])
|
||||
if keys:
|
||||
env[keys[0]] = url
|
||||
|
||||
|
||||
def load_dotenv(path: Path) -> dict[str, str]:
|
||||
out: dict[str, str] = {}
|
||||
if not path.is_file():
|
||||
@@ -388,6 +440,9 @@ def main() -> int:
|
||||
args = ap.parse_args()
|
||||
|
||||
env = load_dotenv(args.env)
|
||||
merge_rpc_os_into(env)
|
||||
apply_eth_mainnet_rpc_alias(env)
|
||||
apply_infura_rpc_defaults(env)
|
||||
dep = deployer_address(env, args.deployer)
|
||||
if not dep:
|
||||
print("No deployer: set PRIVATE_KEY or DEPLOYER_ADDRESS in .env or pass --deployer", file=sys.stderr)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# Resume mainnet cWUSDC EI matrix mints from ei-matrix-cwusdc-mint-last-idx.txt + 1.
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
exec "$SCRIPT_DIR/mint-cwusdc-ei-matrix-wallets.sh" --resume-next "$@"
|
||||
89
scripts/deployment/deploy-engine-x-indexed-liquidity-vault-mainnet.sh
Executable file
89
scripts/deployment/deploy-engine-x-indexed-liquidity-vault-mainnet.sh
Executable file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
|
||||
FEE="${ENGINE_X_UNIV3_FEE:-100}"
|
||||
MAX_ABS_TICK="${ENGINE_X_INDEXED_MAX_ABS_TICK:-100}"
|
||||
MIN_LIQUIDITY="${ENGINE_X_INDEXED_MIN_LIQUIDITY:-1}"
|
||||
MAX_PROOF_SWAP_AMOUNT="${ENGINE_X_INDEXED_MAX_PROOF_SWAP_AMOUNT:-1000000}"
|
||||
VERIFY="${VERIFY:-1}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
|
||||
OWNER="${ENGINE_X_INDEXED_OWNER:-${DEPLOYER_ADDRESS:-}}"
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
OWNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
fi
|
||||
if [[ -z "${OWNER}" ]]; then
|
||||
echo "Set PRIVATE_KEY, DEPLOYER_ADDRESS, or ENGINE_X_INDEXED_OWNER" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOKEN0="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '1p')"
|
||||
TOKEN1="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '2p')"
|
||||
POOL="${ENGINE_X_UNIV3_POOL:-$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)}"
|
||||
|
||||
if [[ "${POOL}" == "0x0000000000000000000000000000000000000000" ]]; then
|
||||
cat <<EOF
|
||||
Engine X indexed-liquidity vault deployment blocked
|
||||
UniV3 cWUSDC/USDC pool is not deployed for fee ${FEE}.
|
||||
Create/fund the public pool first, then rerun this script.
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
VERIFY_ARGS=()
|
||||
if [[ "${VERIFY}" == "1" ]]; then
|
||||
VERIFY_ARGS+=(--verify)
|
||||
fi
|
||||
|
||||
CREATE_CMD_EXEC=(
|
||||
forge create
|
||||
--broadcast
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
--private-key "${PRIVATE_KEY:-}"
|
||||
"${VERIFY_ARGS[@]}"
|
||||
contracts/flash/DBISEngineXIndexedLiquidityVault.sol:DBISEngineXIndexedLiquidityVault
|
||||
--constructor-args
|
||||
"${CWUSDC}" "${USDC}" "${POOL}" "${OWNER}" "${MAX_ABS_TICK}" "${MIN_LIQUIDITY}" "${MAX_PROOF_SWAP_AMOUNT}"
|
||||
)
|
||||
|
||||
cat <<EOF
|
||||
Engine X indexed-liquidity vault deployment plan
|
||||
mode: ${EXECUTE}
|
||||
owner: ${OWNER}
|
||||
cWUSDC: ${CWUSDC}
|
||||
USDC: ${USDC}
|
||||
UniV3 pool: ${POOL}
|
||||
fee: ${FEE}
|
||||
max abs tick: ${MAX_ABS_TICK}
|
||||
min liquidity: ${MIN_LIQUIDITY}
|
||||
max proof swap amount raw: ${MAX_PROOF_SWAP_AMOUNT}
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. Review command:
|
||||
cd smom-dbis-138
|
||||
forge create --broadcast --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" ${VERIFY_ARGS[*]} contracts/flash/DBISEngineXIndexedLiquidityVault.sol:DBISEngineXIndexedLiquidityVault --constructor-args "${CWUSDC}" "${USDC}" "${POOL}" "${OWNER}" "${MAX_ABS_TICK}" "${MIN_LIQUIDITY}" "${MAX_PROOF_SWAP_AMOUNT}"
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
|
||||
"${CREATE_CMD_EXEC[@]}"
|
||||
popd >/dev/null
|
||||
118
scripts/deployment/deploy-engine-x-v2-mainnet.sh
Executable file
118
scripts/deployment/deploy-engine-x-v2-mainnet.sh
Executable file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
XAUT="${XAUT_MAINNET:-0x68749665FF8D2d112Fa859AA293F07A622782F38}"
|
||||
XAUT_USD_PRICE6="${ENGINE_X_XAUT_USD_PRICE6:-3226640000}"
|
||||
LTV_BPS="${ENGINE_X_LTV_BPS:-8000}"
|
||||
MAX_ROUND_TRIP_LOSS_BPS="${ENGINE_X_MAX_ROUND_TRIP_LOSS_BPS:-100}"
|
||||
POOL_CWUSDC_RAW="${ENGINE_X_POOL_CWUSDC_RAW:-85763529}"
|
||||
POOL_USDC_RAW="${ENGINE_X_POOL_USDC_RAW:-85763529}"
|
||||
LENDER_USDC_RAW="${ENGINE_X_LENDER_USDC_RAW:-5000000}"
|
||||
FLASH_FEE_BPS="${ENGINE_X_FLASH_FEE_BPS:-5}"
|
||||
MAX_FLASH_LOAN_RAW="${ENGINE_X_MAX_FLASH_LOAN_RAW:-0}"
|
||||
SEED_AFTER_DEPLOY="${SEED_AFTER_DEPLOY:-0}"
|
||||
VERIFY="${VERIFY:-1}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
|
||||
OWNER="${ENGINE_X_OWNER:-${DEPLOYER_ADDRESS:-}}"
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
OWNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
fi
|
||||
SURPLUS_RECEIVER="${ENGINE_X_SURPLUS_RECEIVER:-${OWNER}}"
|
||||
|
||||
if [[ -z "${OWNER}" || -z "${SURPLUS_RECEIVER}" ]]; then
|
||||
echo "Set PRIVATE_KEY, DEPLOYER_ADDRESS, ENGINE_X_OWNER, and/or ENGINE_X_SURPLUS_RECEIVER" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERIFY_ARGS=()
|
||||
if [[ "${VERIFY}" == "1" ]]; then
|
||||
VERIFY_ARGS+=(--verify)
|
||||
fi
|
||||
|
||||
CREATE_CMD_EXEC=(
|
||||
forge create
|
||||
--broadcast
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
--private-key "${PRIVATE_KEY:-}"
|
||||
"${VERIFY_ARGS[@]}"
|
||||
contracts/flash/DBISEngineXVirtualBatchVault.sol:DBISEngineXVirtualBatchVault
|
||||
--constructor-args
|
||||
"${CWUSDC}" "${USDC}" "${XAUT}" "${OWNER}" "${SURPLUS_RECEIVER}"
|
||||
"${XAUT_USD_PRICE6}" "${LTV_BPS}" "${MAX_ROUND_TRIP_LOSS_BPS}"
|
||||
)
|
||||
|
||||
cat <<EOF
|
||||
Engine X v2 Mainnet deployment plan
|
||||
mode: ${EXECUTE}
|
||||
owner: ${OWNER}
|
||||
surplus receiver: ${SURPLUS_RECEIVER}
|
||||
cWUSDC: ${CWUSDC}
|
||||
USDC: ${USDC}
|
||||
XAUt: ${XAUT}
|
||||
XAUt price6: ${XAUT_USD_PRICE6}
|
||||
LTV bps: ${LTV_BPS}
|
||||
max round-trip loss bps: ${MAX_ROUND_TRIP_LOSS_BPS}
|
||||
default seed: ${POOL_CWUSDC_RAW} cWUSDC raw / ${POOL_USDC_RAW} USDC raw
|
||||
lender bucket: ${LENDER_USDC_RAW} USDC raw
|
||||
flash fee bps: ${FLASH_FEE_BPS}
|
||||
max flash loan raw: ${MAX_FLASH_LOAN_RAW}
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. Review commands:
|
||||
cd smom-dbis-138
|
||||
forge create --broadcast --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" ${VERIFY_ARGS[*]} contracts/flash/DBISEngineXVirtualBatchVault.sol:DBISEngineXVirtualBatchVault --constructor-args "${CWUSDC}" "${USDC}" "${XAUT}" "${OWNER}" "${SURPLUS_RECEIVER}" "${XAUT_USD_PRICE6}" "${LTV_BPS}" "${MAX_ROUND_TRIP_LOSS_BPS}"
|
||||
|
||||
After deploy, export the new address:
|
||||
export DBIS_ENGINE_X_V2_VAULT=<deployed-vault-address>
|
||||
|
||||
Optional seed/fund/risk controls:
|
||||
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'setFlashFeeBps(uint256)' "${FLASH_FEE_BPS}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'setMaxFlashLoanAmount(uint256)' "${MAX_FLASH_LOAN_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${CWUSDC}" 'approve(address,uint256)' "\$DBIS_ENGINE_X_V2_VAULT" "${POOL_CWUSDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${USDC}" 'approve(address,uint256)' "\$DBIS_ENGINE_X_V2_VAULT" "$((POOL_USDC_RAW + LENDER_USDC_RAW))" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'seedPool(uint256,uint256)' "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "\$DBIS_ENGINE_X_V2_VAULT" 'fundLender(uint256)' "${LENDER_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
|
||||
DEPLOY_OUT="$("${CREATE_CMD_EXEC[@]}")"
|
||||
popd >/dev/null
|
||||
printf '%s\n' "${DEPLOY_OUT}"
|
||||
|
||||
VAULT="$(printf '%s\n' "${DEPLOY_OUT}" | grep -oE 'Deployed to: 0x[a-fA-F0-9]{40}' | awk '{print $3}' | tail -1)"
|
||||
if [[ -z "${VAULT}" ]]; then
|
||||
echo "Could not parse deployed vault address" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cast send "${VAULT}" 'setFlashFeeBps(uint256)' "${FLASH_FEE_BPS}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${VAULT}" 'setMaxFlashLoanAmount(uint256)' "${MAX_FLASH_LOAN_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
|
||||
if [[ "${SEED_AFTER_DEPLOY}" == "1" ]]; then
|
||||
cast send "${CWUSDC}" 'approve(address,uint256)' "${VAULT}" "${POOL_CWUSDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${USDC}" 'approve(address,uint256)' "${VAULT}" "$((POOL_USDC_RAW + LENDER_USDC_RAW))" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${VAULT}" 'seedPool(uint256,uint256)' "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${VAULT}" 'fundLender(uint256)' "${LENDER_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
fi
|
||||
|
||||
echo "DBIS_ENGINE_X_V2_VAULT=${VAULT}"
|
||||
99
scripts/deployment/deploy-engine-x-xaut-usdc-borrow-vault-mainnet.sh
Executable file
99
scripts/deployment/deploy-engine-x-xaut-usdc-borrow-vault-mainnet.sh
Executable file
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
XAUT="${XAUT_MAINNET:-0x68749665FF8D2d112Fa859AA293F07A622782F38}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
XAUT_USD_PRICE6="${ENGINE_X_XAUT_USD_PRICE6:-3226640000}"
|
||||
LTV_BPS="${ENGINE_X_BORROW_LTV_BPS:-7500}"
|
||||
LIQUIDATION_THRESHOLD_BPS="${ENGINE_X_BORROW_LIQUIDATION_THRESHOLD_BPS:-8000}"
|
||||
MIN_HEALTH_FACTOR_BPS="${ENGINE_X_BORROW_MIN_HEALTH_FACTOR_BPS:-11000}"
|
||||
LIQUIDATION_BONUS_BPS="${ENGINE_X_BORROW_LIQUIDATION_BONUS_BPS:-500}"
|
||||
MAX_BORROW_USDC_RAW="${ENGINE_X_BORROW_MAX_USDC_RAW:-0}"
|
||||
PRICE_SOURCE_HASH="${ENGINE_X_XAUT_PRICE_SOURCE_HASH:-$(cast keccak "dbis-engine-x:xaut-usd-price6:${XAUT_USD_PRICE6}")}"
|
||||
VERIFY="${VERIFY:-1}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
|
||||
OWNER="${ENGINE_X_BORROW_OWNER:-${DEPLOYER_ADDRESS:-}}"
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
OWNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
fi
|
||||
|
||||
if [[ -z "${OWNER}" ]]; then
|
||||
echo "Set PRIVATE_KEY, DEPLOYER_ADDRESS, or ENGINE_X_BORROW_OWNER" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERIFY_ARGS=()
|
||||
if [[ "${VERIFY}" == "1" ]]; then
|
||||
VERIFY_ARGS+=(--verify)
|
||||
fi
|
||||
|
||||
CREATE_CMD_EXEC=(
|
||||
forge create
|
||||
--broadcast
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
--private-key "${PRIVATE_KEY:-}"
|
||||
"${VERIFY_ARGS[@]}"
|
||||
contracts/flash/DBISEngineXXautUsdcBorrowVault.sol:DBISEngineXXautUsdcBorrowVault
|
||||
--constructor-args
|
||||
"${XAUT}" "${USDC}" "${CWUSDC}" "${OWNER}"
|
||||
"${XAUT_USD_PRICE6}" "${LTV_BPS}" "${LIQUIDATION_THRESHOLD_BPS}" "${MIN_HEALTH_FACTOR_BPS}"
|
||||
"${LIQUIDATION_BONUS_BPS}" "${MAX_BORROW_USDC_RAW}" "${PRICE_SOURCE_HASH}"
|
||||
)
|
||||
|
||||
cat <<EOF
|
||||
Engine X XAUt/USDC borrow vault deployment plan
|
||||
mode: ${EXECUTE}
|
||||
owner: ${OWNER}
|
||||
XAUt: ${XAUT}
|
||||
USDC: ${USDC}
|
||||
cWUSDC proof token: ${CWUSDC}
|
||||
XAUt price6: ${XAUT_USD_PRICE6}
|
||||
price source hash: ${PRICE_SOURCE_HASH}
|
||||
LTV bps: ${LTV_BPS}
|
||||
liquidation threshold bps: ${LIQUIDATION_THRESHOLD_BPS}
|
||||
min health factor bps: ${MIN_HEALTH_FACTOR_BPS}
|
||||
liquidation bonus bps: ${LIQUIDATION_BONUS_BPS}
|
||||
max borrow USDC raw: ${MAX_BORROW_USDC_RAW}
|
||||
|
||||
Boundary:
|
||||
The vault lends only pre-funded official USDC. It does not create USDC and it
|
||||
does not accept cWUSDC as debt repayment. cWUSDC-sourced repayment proofs still
|
||||
settle with actual USDC and only attach public swap/audit/peg hashes.
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. Review command:
|
||||
cd smom-dbis-138
|
||||
forge create --broadcast --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" ${VERIFY_ARGS[*]} contracts/flash/DBISEngineXXautUsdcBorrowVault.sol:DBISEngineXXautUsdcBorrowVault --constructor-args "${XAUT}" "${USDC}" "${CWUSDC}" "${OWNER}" "${XAUT_USD_PRICE6}" "${LTV_BPS}" "${LIQUIDATION_THRESHOLD_BPS}" "${MIN_HEALTH_FACTOR_BPS}" "${LIQUIDATION_BONUS_BPS}" "${MAX_BORROW_USDC_RAW}" "${PRICE_SOURCE_HASH}"
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
|
||||
DEPLOY_OUT="$("${CREATE_CMD_EXEC[@]}")"
|
||||
popd >/dev/null
|
||||
printf '%s\n' "${DEPLOY_OUT}"
|
||||
|
||||
VAULT="$(printf '%s\n' "${DEPLOY_OUT}" | grep -oE 'Deployed to: 0x[a-fA-F0-9]{40}' | awk '{print $3}' | tail -1)"
|
||||
if [[ -z "${VAULT}" ]]; then
|
||||
echo "Could not parse deployed borrow vault address" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "DBIS_ENGINE_X_XAUT_USDC_BORROW_VAULT=${VAULT}"
|
||||
238
scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh
Executable file
238
scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh
Executable file
@@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
VAULT="${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}"
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
|
||||
POSITION_MANAGER="${CHAIN_1_UNISWAP_V3_POSITION_MANAGER:-0xC36442b4a4522E871399CD717aBDD847Ab11FE88}"
|
||||
FEE="${ENGINE_X_UNIV3_FEE:-100}"
|
||||
TICK_LOWER="${ENGINE_X_UNIV3_TICK_LOWER:--100}"
|
||||
TICK_UPPER="${ENGINE_X_UNIV3_TICK_UPPER:-100}"
|
||||
SQRT_PRICE_X96="${ENGINE_X_UNIV3_SQRT_PRICE_X96:-79228162514264337593543950336}"
|
||||
DEADLINE_SECONDS="${DEADLINE_SECONDS:-1800}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
INCLUDE_LENDER_USDC="${INCLUDE_LENDER_USDC:-0}"
|
||||
MIGRATION_AMOUNT_RAW="${MIGRATION_AMOUNT_RAW:-}"
|
||||
|
||||
OWNER="$(cast call "${VAULT}" 'owner()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
|
||||
SIGNER="${DEPLOYER_ADDRESS:-${OWNER}}"
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
fi
|
||||
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${EXECUTE}" == "1" && "${SIGNER,,}" != "${OWNER,,}" ]]; then
|
||||
echo "EXECUTE=1 signer must be the Engine X vault owner" >&2
|
||||
echo " signer: ${SIGNER}" >&2
|
||||
echo " owner: ${OWNER}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
VAULT_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
VAULT_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
FEE_TICK_SPACING="$(cast call "${FACTORY}" 'feeAmountTickSpacing(uint24)(int24)' "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
ACCOUNTING_AWARE_SUPPORTED="0"
|
||||
if cast call "${VAULT}" 'maxFlashLoan(address)(uint256)' "${USDC}" --rpc-url "${ETHEREUM_MAINNET_RPC}" >/dev/null 2>&1; then
|
||||
ACCOUNTING_AWARE_SUPPORTED="1"
|
||||
fi
|
||||
|
||||
if [[ "${FEE_TICK_SPACING}" == "0" ]]; then
|
||||
echo "Uniswap v3 fee tier is not enabled on the configured factory: ${FEE}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && "${ACCOUNTING_AWARE_SUPPORTED}" != "1" ]]; then
|
||||
echo "EXECUTE=1 requires an upgraded accounting-aware Engine X vault" >&2
|
||||
echo " vault: ${VAULT}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eval "$(
|
||||
python3 - "${CWUSDC}" "${USDC}" "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" \
|
||||
"${LENDER_USDC_RAW}" "${VAULT_CWUSDC_RAW}" "${VAULT_USDC_RAW}" \
|
||||
"${INCLUDE_LENDER_USDC}" "${MIGRATION_AMOUNT_RAW}" "${FEE_TICK_SPACING}" \
|
||||
"${TICK_LOWER}" "${TICK_UPPER}" <<'PY'
|
||||
from decimal import Decimal
|
||||
import sys
|
||||
|
||||
(
|
||||
cwusdc,
|
||||
usdc,
|
||||
pool_cw,
|
||||
pool_usdc,
|
||||
lender_usdc,
|
||||
vault_cw,
|
||||
vault_usdc,
|
||||
include_lender,
|
||||
override_amount,
|
||||
spacing,
|
||||
tick_lower,
|
||||
tick_upper,
|
||||
) = sys.argv[1:]
|
||||
|
||||
pool_cw = int(pool_cw)
|
||||
pool_usdc = int(pool_usdc)
|
||||
lender_usdc = int(lender_usdc)
|
||||
vault_cw = int(vault_cw)
|
||||
vault_usdc = int(vault_usdc)
|
||||
spacing = int(spacing)
|
||||
tick_lower = int(tick_lower)
|
||||
tick_upper = int(tick_upper)
|
||||
|
||||
if tick_lower >= tick_upper:
|
||||
raise SystemExit("tick lower must be less than tick upper")
|
||||
if tick_lower % spacing != 0 or tick_upper % spacing != 0:
|
||||
raise SystemExit(f"ticks must be multiples of tick spacing {spacing}")
|
||||
|
||||
available_usdc = vault_usdc if include_lender == "1" else max(vault_usdc - lender_usdc, 0)
|
||||
amount = min(pool_cw, pool_usdc, vault_cw, available_usdc)
|
||||
if override_amount:
|
||||
amount = int(override_amount)
|
||||
if amount <= 0:
|
||||
raise SystemExit("no balanced vault liquidity is available to migrate")
|
||||
if amount > vault_cw:
|
||||
raise SystemExit("migration amount exceeds vault cWUSDC balance")
|
||||
if amount > vault_usdc:
|
||||
raise SystemExit("migration amount exceeds vault USDC balance")
|
||||
if include_lender != "1" and amount > available_usdc:
|
||||
raise SystemExit("migration amount would consume lender USDC; set INCLUDE_LENDER_USDC=1 only if intentional")
|
||||
|
||||
addrs = sorted([cwusdc.lower(), usdc.lower()])
|
||||
token0, token1 = addrs
|
||||
amount0 = amount if token0 == cwusdc.lower() else amount
|
||||
amount1 = amount if token1 == usdc.lower() else amount
|
||||
|
||||
def units(raw: int) -> str:
|
||||
return f"{Decimal(raw) / Decimal(10**6):f}"
|
||||
|
||||
def emit(name, value):
|
||||
print(f"{name}='{value}'")
|
||||
|
||||
emit("TOKEN0", token0)
|
||||
emit("TOKEN1", token1)
|
||||
emit("AMOUNT0_RAW", amount0)
|
||||
emit("AMOUNT1_RAW", amount1)
|
||||
emit("MIGRATE_RAW", amount)
|
||||
emit("MIGRATE_UNITS", units(amount))
|
||||
emit("POOL_CWUSDC_UNITS", units(pool_cw))
|
||||
emit("POOL_USDC_UNITS", units(pool_usdc))
|
||||
emit("LENDER_USDC_UNITS", units(lender_usdc))
|
||||
emit("VAULT_CWUSDC_UNITS", units(vault_cw))
|
||||
emit("VAULT_USDC_UNITS", units(vault_usdc))
|
||||
emit("POOL_USDC_AVAILABLE_FOR_MIGRATION_RAW", available_usdc)
|
||||
emit("POOL_USDC_AVAILABLE_FOR_MIGRATION_UNITS", units(available_usdc))
|
||||
PY
|
||||
)"
|
||||
|
||||
POOL="$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
|
||||
SIMULATED_POOL=""
|
||||
if [[ "${POOL}" == "0x0000000000000000000000000000000000000000" ]]; then
|
||||
SIMULATED_POOL="$(cast call "${POSITION_MANAGER}" 'createAndInitializePoolIfNecessary(address,address,uint24,uint160)(address)' \
|
||||
"${TOKEN0}" "${TOKEN1}" "${FEE}" "${SQRT_PRICE_X96}" --rpc-url "${ETHEREUM_MAINNET_RPC}" \
|
||||
| grep -oE '0x[a-fA-F0-9]{40}' | head -1 || true)"
|
||||
fi
|
||||
|
||||
POOL_SLOT0=""
|
||||
POOL_LIQUIDITY=""
|
||||
if [[ "${POOL}" != "0x0000000000000000000000000000000000000000" ]]; then
|
||||
POOL_SLOT0="$(cast call "${POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
|
||||
POOL_LIQUIDITY="$(cast call "${POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
fi
|
||||
|
||||
DEADLINE="$(( $(date +%s) + DEADLINE_SECONDS ))"
|
||||
|
||||
cat <<EOF
|
||||
Engine X indexed-liquidity migration plan
|
||||
mode: ${EXECUTE}
|
||||
vault: ${VAULT}
|
||||
vault owner: ${OWNER}
|
||||
signer/recipient: ${SIGNER}
|
||||
|
||||
Engine X virtual vault state
|
||||
accounted pool: ${POOL_CWUSDC_UNITS} cWUSDC / ${POOL_USDC_UNITS} USDC
|
||||
lender bucket: ${LENDER_USDC_UNITS} USDC
|
||||
actual token balances: ${VAULT_CWUSDC_UNITS} cWUSDC / ${VAULT_USDC_UNITS} USDC
|
||||
USDC available without lender bucket: ${POOL_USDC_AVAILABLE_FOR_MIGRATION_UNITS}
|
||||
|
||||
Uniswap v3 public proof surface
|
||||
factory: ${FACTORY}
|
||||
position manager: ${POSITION_MANAGER}
|
||||
fee: ${FEE}
|
||||
tick spacing: ${FEE_TICK_SPACING}
|
||||
ticks: [${TICK_LOWER}, ${TICK_UPPER}]
|
||||
initial sqrtPriceX96: ${SQRT_PRICE_X96}
|
||||
existing pool: ${POOL}
|
||||
simulated pool if created: ${SIMULATED_POOL:-n/a}
|
||||
existing slot0: ${POOL_SLOT0:-n/a}
|
||||
existing liquidity: ${POOL_LIQUIDITY:-n/a}
|
||||
|
||||
Migration sizing
|
||||
migrate: ${MIGRATE_UNITS} cWUSDC + ${MIGRATE_UNITS} USDC
|
||||
token0: ${TOKEN0} amount0 raw: ${AMOUNT0_RAW}
|
||||
token1: ${TOKEN1} amount1 raw: ${AMOUNT1_RAW}
|
||||
|
||||
Boundary
|
||||
This migrates tiny Engine X proof liquidity into a public indexable UniV3 position.
|
||||
It does not meet the 2,500/2,500 policy floor or the 10,000/10,000 preferred evidence target.
|
||||
accounting-aware vault APIs detected: ${ACCOUNTING_AWARE_SUPPORTED}
|
||||
If this is 0, deploy the upgraded Engine X vault before broadcasting the migration.
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
if [[ "${ACCOUNTING_AWARE_SUPPORTED}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. No broadcast commands were emitted for this vault because it does not expose
|
||||
the upgraded accounting-aware API. Deploy the upgraded Engine X vault, seed/migrate the
|
||||
balanced proof liquidity into that vault, then rerun with:
|
||||
ENGINE_X_VAULT=<upgraded-vault-address> EXECUTE=0 bash scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. Review these commands before any broadcast:
|
||||
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${SIGNER}" "${MIGRATE_RAW}" "${MIGRATE_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${POSITION_MANAGER}" 'createAndInitializePoolIfNecessary(address,address,uint24,uint160)' "${TOKEN0}" "${TOKEN1}" "${FEE}" "${SQRT_PRICE_X96}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${TOKEN0}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT0_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${TOKEN1}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT1_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${POSITION_MANAGER}" 'mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))' "(${TOKEN0},${TOKEN1},${FEE},${TICK_LOWER},${TICK_UPPER},${AMOUNT0_RAW},${AMOUNT1_RAW},0,0,${SIGNER},${DEADLINE})" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY" -vv
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${SIGNER}" "${MIGRATE_RAW}" "${MIGRATE_RAW}" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
|
||||
cast send "${POSITION_MANAGER}" 'createAndInitializePoolIfNecessary(address,address,uint24,uint160)' \
|
||||
"${TOKEN0}" "${TOKEN1}" "${FEE}" "${SQRT_PRICE_X96}" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
|
||||
cast send "${TOKEN0}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT0_RAW}" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${TOKEN1}" 'approve(address,uint256)' "${POSITION_MANAGER}" "${AMOUNT1_RAW}" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
|
||||
cast send "${POSITION_MANAGER}" 'mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256))' \
|
||||
"(${TOKEN0},${TOKEN1},${FEE},${TICK_LOWER},${TICK_UPPER},${AMOUNT0_RAW},${AMOUNT1_RAW},0,0,${SIGNER},${DEADLINE})" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}" -vv
|
||||
|
||||
NEW_POOL="$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
|
||||
echo "Post-migration UniV3 pool: ${NEW_POOL}"
|
||||
cast call "${NEW_POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
cast call "${NEW_POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
339
scripts/deployment/mint-cwusdc-ei-matrix-wallets.sh
Normal file
339
scripts/deployment/mint-cwusdc-ei-matrix-wallets.sh
Normal file
@@ -0,0 +1,339 @@
|
||||
#!/usr/bin/env bash
|
||||
# Mint Ethereum mainnet cWUSDC directly to each address in config/pmm-soak-wallet-grid.json
|
||||
# (EI matrix). Requires PRIVATE_KEY with MINTER_ROLE on the cWUSDC token.
|
||||
#
|
||||
# Modes (exactly one):
|
||||
# --mint-raw R Same raw units minted to every wallet in the slice.
|
||||
# --total-mint-raw B Total supply to mint across the slice, split with ±spread
|
||||
# then renormalized to B (same algorithm as transfer distribution).
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/deployment/mint-cwusdc-ei-matrix-wallets.sh [--dry-run] [--limit N] [--offset N|--resume-next]
|
||||
# (--mint-raw R | --total-mint-raw B [--spread-pct S])
|
||||
#
|
||||
# --quiet-dry-run With --dry-run, suppress per-wallet lines.
|
||||
# --legacy Pass --legacy to cast send.
|
||||
#
|
||||
# Env: ETHEREUM_MAINNET_RPC, CWUSDC_MAINNET, PRIVATE_KEY,
|
||||
# EI_MATRIX_MINT_GAS_EST (default 60000), EI_MATRIX_GAS_HEADROOM_BPS (default 10500),
|
||||
# EI_MATRIX_SKIP_GAS_CHECK=1 to bypass ETH preflight.
|
||||
#
|
||||
# Progress: reports/status/ei-matrix-cwusdc-mint-last-idx.txt
|
||||
# Failures: reports/status/ei-matrix-cwusdc-mint-failures.log
|
||||
# Lock: reports/status/ei-matrix-cwusdc-mint.lock
|
||||
#
|
||||
# On-chain: cWUSDC uses CompliantWrappedToken-style mint(address,uint256) for MINTER_ROLE.
|
||||
# If mint reverts (reserve policy, roles), fix on-chain state before retrying.
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
DRY_RUN=false
|
||||
LIMIT=""
|
||||
OFFSET="0"
|
||||
OFFSET_EXPLICIT=false
|
||||
RESUME_NEXT=false
|
||||
SPREAD_PCT="${EI_MATRIX_SPREAD_PCT:-15}"
|
||||
CAST_LEGACY=false
|
||||
QUIET_DRY_RUN=false
|
||||
MINT_RAW=""
|
||||
TOTAL_MINT_RAW=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dry-run) DRY_RUN=true; shift ;;
|
||||
--quiet-dry-run) QUIET_DRY_RUN=true; shift ;;
|
||||
--limit) LIMIT="${2:?}"; shift 2 ;;
|
||||
--resume-next) RESUME_NEXT=true; shift ;;
|
||||
--offset) OFFSET="${2:?}"; OFFSET_EXPLICIT=true; shift 2 ;;
|
||||
--spread-pct) SPREAD_PCT="${2:?}"; shift 2 ;;
|
||||
--mint-raw) MINT_RAW="${2:?}"; shift 2 ;;
|
||||
--total-mint-raw) TOTAL_MINT_RAW="${2:?}"; shift 2 ;;
|
||||
--legacy) CAST_LEGACY=true; shift ;;
|
||||
*) echo "Unknown arg: $1" >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
LAST_IDX_FILE="${EI_MATRIX_CWUSDC_MINT_LAST_IDX_FILE:-${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint-last-idx.txt}"
|
||||
if $RESUME_NEXT && $OFFSET_EXPLICIT; then
|
||||
echo "Use only one of --offset or --resume-next." >&2
|
||||
exit 1
|
||||
fi
|
||||
if $RESUME_NEXT; then
|
||||
[[ -f "$LAST_IDX_FILE" ]] || { echo "Missing last-index file for --resume-next: $LAST_IDX_FILE" >&2; exit 1; }
|
||||
_last="$(tr -d '[:space:]' < "$LAST_IDX_FILE" || echo "")"
|
||||
[[ -n "$_last" ]] || { echo "Empty $LAST_IDX_FILE" >&2; exit 1; }
|
||||
OFFSET=$((_last + 1))
|
||||
echo "Resume-next (mint): last completed idx=$_last → offset=$OFFSET"
|
||||
fi
|
||||
|
||||
if [[ -n "$MINT_RAW" && -n "$TOTAL_MINT_RAW" ]]; then
|
||||
echo "Use only one of --mint-raw or --total-mint-raw." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z "$MINT_RAW" && -z "$TOTAL_MINT_RAW" ]]; then
|
||||
echo "Set --mint-raw or --total-mint-raw." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source "$PROJECT_ROOT/scripts/lib/load-project-env.sh"
|
||||
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
PUBLIC_ETH_RPC="${ETHEREUM_MAINNET_PUBLIC_RPC:-https://ethereum-rpc.publicnode.com}"
|
||||
RPC="${ETHEREUM_MAINNET_RPC:-${RPC_URL_1:-${ETH_MAINNET_RPC_URL:-$PUBLIC_ETH_RPC}}}"
|
||||
BALANCE_RPC="${EI_MATRIX_BALANCE_RPC:-$RPC}"
|
||||
|
||||
LOCK_FILE="${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint.lock"
|
||||
MANIFEST_DIR="${PROJECT_ROOT}/reports/status"
|
||||
mkdir -p "$MANIFEST_DIR"
|
||||
exec 200>"$LOCK_FILE"
|
||||
if ! flock -n 200; then
|
||||
echo "Another mint-cwusdc-ei-matrix-wallets.sh is already running (lock: $LOCK_FILE)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GRID="$PROJECT_ROOT/config/pmm-soak-wallet-grid.json"
|
||||
DEPLOYER_CANONICAL="0x4A666F96fC8764181194447A7dFdb7d471b301C8"
|
||||
|
||||
[[ -f "$GRID" ]] || { echo "Missing $GRID" >&2; exit 1; }
|
||||
command -v cast &>/dev/null || { echo "cast required" >&2; exit 1; }
|
||||
command -v jq &>/dev/null || { echo "jq required" >&2; exit 1; }
|
||||
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY not set" >&2; exit 1; }
|
||||
|
||||
FROM_ADDR=$(cast wallet address --private-key "$PRIVATE_KEY")
|
||||
CHAIN_ID=$(cast chain-id --rpc-url "$RPC" 2>/dev/null | tr -d '[:space:]' || true)
|
||||
[[ -n "$CHAIN_ID" ]] || CHAIN_ID="1"
|
||||
if [[ "$CHAIN_ID" != "1" ]]; then
|
||||
echo "[WARN] chain-id=$CHAIN_ID (expected 1)." >&2
|
||||
fi
|
||||
|
||||
pending_nonce() {
|
||||
local resp hex
|
||||
resp=$(curl -sS -X POST "$RPC" -H "Content-Type: application/json" \
|
||||
-d "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionCount\",\"params\":[\"${FROM_ADDR}\",\"pending\"],\"id\":1}" 2>/dev/null) || return 1
|
||||
hex=$(echo "$resp" | jq -r '.result // empty')
|
||||
[[ -n "$hex" ]] || return 1
|
||||
cast to-dec "$hex"
|
||||
}
|
||||
|
||||
token_decimals() {
|
||||
cast call "$CWUSDC" 'decimals()(uint8)' --rpc-url "$BALANCE_RPC" 2>/dev/null | awk '{print $1}'
|
||||
}
|
||||
|
||||
generate_spread_amounts_raw() {
|
||||
local count="$1" budget="$2" spread="$3"
|
||||
python3 - "$count" "$budget" "$spread" <<'PY'
|
||||
import random
|
||||
import sys
|
||||
n = int(sys.argv[1])
|
||||
budget = int(sys.argv[2])
|
||||
spread = float(sys.argv[3])
|
||||
if n <= 0:
|
||||
sys.exit("count must be positive")
|
||||
if budget < 0:
|
||||
sys.exit("budget must be non-negative")
|
||||
if spread < 0 or spread > 100:
|
||||
sys.exit("spread-pct must be in [0, 100]")
|
||||
base = 10000
|
||||
low_w = max(1, (100 * base - int(spread * base)) // 100)
|
||||
high_w = (100 * base + int(spread * base)) // 100
|
||||
w = [random.randint(low_w, high_w) for _ in range(n)]
|
||||
s = sum(w)
|
||||
raw = [(budget * wi) // s for wi in w]
|
||||
rem = budget - sum(raw)
|
||||
for i in range(rem):
|
||||
raw[i % n] += 1
|
||||
for x in raw:
|
||||
print(x)
|
||||
PY
|
||||
}
|
||||
|
||||
stream_addresses() {
|
||||
if [[ -n "${LIMIT:-}" ]]; then
|
||||
jq -r --argjson o "$OFFSET" --argjson l "$LIMIT" '.wallets[$o:$o+$l][] | .address' "$GRID"
|
||||
else
|
||||
jq -r --argjson o "$OFFSET" '.wallets[$o:][] | .address' "$GRID"
|
||||
fi
|
||||
}
|
||||
|
||||
ERR_LOG="${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint-failures.log"
|
||||
LAST_IDX="${PROJECT_ROOT}/reports/status/ei-matrix-cwusdc-mint-last-idx.txt"
|
||||
|
||||
matrix_try_mint() {
|
||||
local addr="$1" raw_amt="$2" idx="$3"
|
||||
local dec human out tx attempt=1
|
||||
dec="${DECIMALS:-6}"
|
||||
if [[ "$raw_amt" == "0" ]]; then
|
||||
echo "[skip] idx=$idx $addr zero raw"
|
||||
return 0
|
||||
fi
|
||||
human=$(python3 -c "d=int('$dec'); a=int('$raw_amt'); print(f'{a / (10**d):.{min(d,8)}f}')" 2>/dev/null || echo "$raw_amt")
|
||||
if $DRY_RUN; then
|
||||
if ! $QUIET_DRY_RUN; then
|
||||
echo "[dry-run] idx=$idx $addr raw=$raw_amt (~$human)"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
local cast_extra=()
|
||||
$CAST_LEGACY && cast_extra+=(--legacy)
|
||||
while [[ "$attempt" -le 2 ]]; do
|
||||
if out=$(cast send "$CWUSDC" "mint(address,uint256)" "$addr" "$raw_amt" \
|
||||
--rpc-url "$RPC" --private-key "$PRIVATE_KEY" \
|
||||
--nonce "$NONCE" "${cast_extra[@]}" 2>&1); then
|
||||
tx=$(echo "$out" | tail -n1)
|
||||
echo "[ok] idx=$idx nonce=$NONCE $addr raw=$raw_amt (~$human) tx=$tx"
|
||||
sent=$((sent + 1))
|
||||
NONCE=$((NONCE + 1))
|
||||
echo "$idx" > "$LAST_IDX"
|
||||
return 0
|
||||
fi
|
||||
if [[ "$attempt" -eq 1 ]] && echo "$out" | grep -qi 'nonce too low'; then
|
||||
NONCE=$(pending_nonce) || true
|
||||
echo "[retry] idx=$idx nonce refreshed to $NONCE (nonce too low)" >&2
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
echo "[fail] idx=$idx nonce=$NONCE $addr $out" | tee -a "$ERR_LOG" >&2
|
||||
failed=$((failed + 1))
|
||||
NONCE=$(pending_nonce) || true
|
||||
return 0
|
||||
done
|
||||
}
|
||||
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "EI matrix cWUSDC mint (mainnet)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
echo "RPC: $RPC"
|
||||
echo "Token: $CWUSDC"
|
||||
echo "Signer: $FROM_ADDR"
|
||||
echo "Grid: $GRID"
|
||||
echo "Dry-run: $DRY_RUN Quiet: $QUIET_DRY_RUN"
|
||||
echo "Offset: $OFFSET Limit: ${LIMIT:-all}"
|
||||
if [[ -n "$MINT_RAW" ]]; then
|
||||
echo "Mode: fixed --mint-raw $MINT_RAW per wallet"
|
||||
else
|
||||
echo "Mode: --total-mint-raw $TOTAL_MINT_RAW spread: ±${SPREAD_PCT}% normalized"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [[ "${FROM_ADDR,,}" != "${DEPLOYER_CANONICAL,,}" ]]; then
|
||||
echo "[WARN] Signer is not canonical deployer $DEPLOYER_CANONICAL — minter role may still be granted."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
DECIMALS=$(token_decimals || echo "6")
|
||||
|
||||
ADDR_TMP=$(mktemp)
|
||||
AMOUNTS_TMP=$(mktemp)
|
||||
cleanup_tmp() {
|
||||
[[ -f "$ADDR_TMP" ]] && rm -f "$ADDR_TMP"
|
||||
[[ -f "$AMOUNTS_TMP" ]] && rm -f "$AMOUNTS_TMP"
|
||||
}
|
||||
trap cleanup_tmp EXIT
|
||||
|
||||
stream_addresses > "$ADDR_TMP"
|
||||
WALLET_COUNT=$(wc -l < "$ADDR_TMP" | tr -d '[:space:]')
|
||||
if [[ -z "$WALLET_COUNT" || "$WALLET_COUNT" -eq 0 ]]; then
|
||||
echo "No wallets in range (offset=$OFFSET limit=${LIMIT:-all})." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "$MINT_RAW" ]]; then
|
||||
awk -v r="$MINT_RAW" '{print r}' "$ADDR_TMP" > "$AMOUNTS_TMP"
|
||||
BUDGET_RAW=$((MINT_RAW * WALLET_COUNT))
|
||||
else
|
||||
BUDGET_RAW="$TOTAL_MINT_RAW"
|
||||
if [[ "$BUDGET_RAW" -le 0 ]]; then
|
||||
echo "total-mint-raw must be positive." >&2
|
||||
exit 1
|
||||
fi
|
||||
generate_spread_amounts_raw "$WALLET_COUNT" "$BUDGET_RAW" "$SPREAD_PCT" > "$AMOUNTS_TMP"
|
||||
fi
|
||||
|
||||
SUM_CHECK=$(awk '{s+=$1} END {print s}' "$AMOUNTS_TMP")
|
||||
if [[ "$SUM_CHECK" != "$BUDGET_RAW" ]]; then
|
||||
echo "INTERNAL: amount sum $SUM_CHECK != budget $BUDGET_RAW" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
AMOUNTS_SHA256=$(sha256sum "$AMOUNTS_TMP" | awk '{print $1}')
|
||||
TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
MANIFEST="$MANIFEST_DIR/ei-matrix-cwusdc-mint-manifest-${TS//:/-}.json"
|
||||
cat >"$MANIFEST" <<EOF
|
||||
{
|
||||
"version": 1,
|
||||
"kind": "ei-matrix-cwusdc-mint",
|
||||
"timestamp": "$TS",
|
||||
"chainId": 1,
|
||||
"token": "$CWUSDC",
|
||||
"signer": "$FROM_ADDR",
|
||||
"offset": $OFFSET,
|
||||
"limit": ${LIMIT:-null},
|
||||
"walletCount": $WALLET_COUNT,
|
||||
"budgetRaw": "$BUDGET_RAW",
|
||||
"fixedMintRaw": ${MINT_RAW:-null},
|
||||
"spreadPct": ${SPREAD_PCT},
|
||||
"amountsSha256": "$AMOUNTS_SHA256",
|
||||
"manifestPath": "$MANIFEST"
|
||||
}
|
||||
EOF
|
||||
echo "Manifest: $MANIFEST"
|
||||
echo "Amounts SHA256: $AMOUNTS_SHA256"
|
||||
echo ""
|
||||
|
||||
GAS_EST="${EI_MATRIX_MINT_GAS_EST:-60000}"
|
||||
HEADROOM_BPS="${EI_MATRIX_GAS_HEADROOM_BPS:-10500}"
|
||||
ETH_WEI=$(cast balance "$FROM_ADDR" --rpc-url "$BALANCE_RPC" 2>/dev/null | awk '{print $1}' || echo "0")
|
||||
ETH_HUMAN=$(python3 -c "print(f'{int(\"$ETH_WEI\") / 1e18:.6f}')" 2>/dev/null || echo "?")
|
||||
echo "Signer ETH (gas): ${ETH_WEI} wei (~$ETH_HUMAN ETH)"
|
||||
|
||||
if ! $DRY_RUN && [[ "${EI_MATRIX_SKIP_GAS_CHECK:-}" != "1" ]]; then
|
||||
GAS_PRICE_WEI=$(cast gas-price --rpc-url "$RPC" 2>/dev/null | awk '{print $1}' | head -1)
|
||||
[[ -n "$GAS_PRICE_WEI" ]] || GAS_PRICE_WEI=0
|
||||
MIN_WEI=$(python3 -c "c=int('$WALLET_COUNT'); g=int('$GAS_EST'); p=int('$GAS_PRICE_WEI'); b=int('$HEADROOM_BPS'); print(c*g*p*b//10000)")
|
||||
if python3 -c "import sys; sys.exit(0 if int('$ETH_WEI') >= int('$MIN_WEI') else 1)"; then
|
||||
echo "Gas preflight OK: est ${GAS_EST} gas/tx × $WALLET_COUNT × gasPrice $GAS_PRICE_WEI × (${HEADROOM_BPS}/10000) ≈ $MIN_WEI wei."
|
||||
else
|
||||
echo "Insufficient ETH for gas preflight. Need ≈ $MIN_WEI wei." >&2
|
||||
echo "Set EI_MATRIX_SKIP_GAS_CHECK=1 to override (operator risk)." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "Sample (first 3, last 3):"
|
||||
_s_idx=$OFFSET
|
||||
while IFS= read -r s_addr && IFS= read -r s_raw <&3; do
|
||||
h=$(python3 -c "d=int('$DECIMALS'); a=int('$s_raw'); print(f'{a / (10**d):.6f}')" 2>/dev/null || echo "$s_raw")
|
||||
echo " idx=$_s_idx $s_addr raw=$s_raw (~$h cWUSDC)"
|
||||
_s_idx=$((_s_idx + 1))
|
||||
done < <(head -3 "$ADDR_TMP") 3< <(head -3 "$AMOUNTS_TMP")
|
||||
_s_idx=$((OFFSET + WALLET_COUNT - 3))
|
||||
while IFS= read -r s_addr && IFS= read -r s_raw <&3; do
|
||||
h=$(python3 -c "d=int('$DECIMALS'); a=int('$s_raw'); print(f'{a / (10**d):.6f}')" 2>/dev/null || echo "$s_raw")
|
||||
echo " idx=$_s_idx $s_addr raw=$s_raw (~$h cWUSDC)"
|
||||
_s_idx=$((_s_idx + 1))
|
||||
done < <(tail -3 "$ADDR_TMP") 3< <(tail -3 "$AMOUNTS_TMP")
|
||||
echo ""
|
||||
|
||||
sent=0
|
||||
failed=0
|
||||
idx=$OFFSET
|
||||
NONCE=$(pending_nonce) || { echo "Could not read pending nonce" >&2; exit 1; }
|
||||
echo "Starting nonce (pending): $NONCE"
|
||||
echo ""
|
||||
|
||||
while IFS=$'\t' read -r addr raw_amt; do
|
||||
matrix_try_mint "$addr" "$raw_amt" "$idx"
|
||||
idx=$((idx + 1))
|
||||
done < <(paste -d $'\t' "$ADDR_TMP" "$AMOUNTS_TMP")
|
||||
|
||||
if $DRY_RUN; then
|
||||
echo "Dry-run complete. Indices covered: $OFFSET..$((idx - 1))."
|
||||
else
|
||||
echo "Done. Mint txs attempted: sent=$sent failed=$failed"
|
||||
fi
|
||||
68
scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh
Normal file
68
scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh
Normal file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
# Single operator pipeline: preflight + mint cWUSDC to every EI matrix wallet on Ethereum mainnet.
|
||||
#
|
||||
# This does NOT bridge from Chain 138 — it mints on mainnet via MINTER_ROLE on CWUSDC_MAINNET.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh --dry-run --mint-raw 1000000
|
||||
# ./scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh --total-mint-raw 1000000000000 --spread-pct 15
|
||||
# ./scripts/deployment/pipeline-ei-matrix-mint-cwusdc.sh --mint-raw 1000000 -- --limit 10 # extra args after --
|
||||
#
|
||||
# Env: loads scripts/lib/load-project-env.sh (PRIVATE_KEY, ETHEREUM_MAINNET_RPC, CWUSDC_MAINNET).
|
||||
#
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
PASS=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
if [[ "$1" == "--" ]]; then shift; PASS+=("$@"); break; fi
|
||||
PASS+=("$1")
|
||||
shift
|
||||
done
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source "$PROJECT_ROOT/scripts/lib/load-project-env.sh"
|
||||
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
PUBLIC_ETH_RPC="${ETHEREUM_MAINNET_PUBLIC_RPC:-https://ethereum-rpc.publicnode.com}"
|
||||
RPC="${ETHEREUM_MAINNET_RPC:-${RPC_URL_1:-${ETH_MAINNET_RPC_URL:-$PUBLIC_ETH_RPC}}}"
|
||||
|
||||
echo "══════════════════════════════════════════════════════════════"
|
||||
echo "Pipeline: EI matrix mainnet cWUSDC mint"
|
||||
echo "══════════════════════════════════════════════════════════════"
|
||||
echo "Grid: config/pmm-soak-wallet-grid.json"
|
||||
echo "Token: $CWUSDC"
|
||||
echo "RPC: $RPC"
|
||||
echo ""
|
||||
|
||||
command -v cast &>/dev/null || { echo "cast required" >&2; exit 1; }
|
||||
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY not set" >&2; exit 1; }
|
||||
|
||||
FROM=$(cast wallet address --private-key "$PRIVATE_KEY")
|
||||
CID=$(cast chain-id --rpc-url "$RPC" 2>/dev/null | tr -d '[:space:]' || echo "?")
|
||||
echo "Signer: $FROM"
|
||||
echo "Chain ID: $CID (expected 1)"
|
||||
if [[ "$CID" != "1" ]]; then
|
||||
echo "[WARN] Not Ethereum mainnet — aborting." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ROLE=$(cast keccak "MINTER_ROLE()")
|
||||
# AccessControl MINTER_ROLE is keccak256 of the string "MINTER_ROLE" for OZ — use cast keccak
|
||||
ROLE=$(cast keccak "MINTER_ROLE")
|
||||
if HR=$(cast call "$CWUSDC" "hasRole(bytes32,address)(bool)" "$ROLE" "$FROM" --rpc-url "$RPC" 2>/dev/null); then
|
||||
if [[ "${HR,,}" != *true* ]]; then
|
||||
echo "[WARN] hasRole(MINTER_ROLE) returned false for signer — mints will likely revert." >&2
|
||||
else
|
||||
echo "Preflight: MINTER_ROLE on cWUSDC for signer — OK"
|
||||
fi
|
||||
else
|
||||
echo "[WARN] Could not call hasRole (ABI may differ) — continuing." >&2
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "→ Running mint-cwusdc-ei-matrix-wallets.sh ${PASS[*]}"
|
||||
echo ""
|
||||
exec "$SCRIPT_DIR/mint-cwusdc-ei-matrix-wallets.sh" "${PASS[@]}"
|
||||
93
scripts/deployment/record-engine-x-indexed-liquidity-proof.sh
Executable file
93
scripts/deployment/record-engine-x-indexed-liquidity-proof.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
if [[ -z "${ENGINE_X_INDEXED_LIQUIDITY_VAULT:-}" ]]; then
|
||||
cat <<'EOF'
|
||||
Engine X indexed proof recording blocked
|
||||
ENGINE_X_INDEXED_LIQUIDITY_VAULT is not configured.
|
||||
Deploy the indexed-liquidity proof vault first:
|
||||
pnpm engine-x:indexed-vault-deploy
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
RECIPIENT="${RECIPIENT:-${DEPLOYER_ADDRESS:-}}"
|
||||
EXACT_OUTPUT_RAW="${EXACT_OUTPUT_RAW:-10000}"
|
||||
PUBLIC_SWAP_TX_HASH_PROVIDED="${PUBLIC_SWAP_TX_HASH+x}"
|
||||
LIQUIDITY_TX_HASH_PROVIDED="${LIQUIDITY_TX_HASH+x}"
|
||||
ISO_HASH_PROVIDED="${ISO_HASH+x}"
|
||||
AUDIT_HASH_PROVIDED="${AUDIT_HASH+x}"
|
||||
PEG_HASH_PROVIDED="${PEG_HASH+x}"
|
||||
PROOF_ID="${PROOF_ID:-$(cast keccak "engine-x:indexed-proof:dry-run:${ENGINE_X_INDEXED_LIQUIDITY_VAULT}:${EXACT_OUTPUT_RAW}")}"
|
||||
PUBLIC_SWAP_TX_HASH="${PUBLIC_SWAP_TX_HASH:-$(cast keccak "engine-x:placeholder:public-swap")}"
|
||||
LIQUIDITY_TX_HASH="${LIQUIDITY_TX_HASH:-$(cast keccak "engine-x:placeholder:liquidity")}"
|
||||
ISO_HASH="${ISO_HASH:-$(cast keccak "engine-x:placeholder:iso")}"
|
||||
AUDIT_HASH="${AUDIT_HASH:-$(cast keccak "engine-x:placeholder:audit")}"
|
||||
PEG_HASH="${PEG_HASH:-$(cast keccak "engine-x:placeholder:peg")}"
|
||||
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
RECIPIENT="${RECIPIENT:-${SIGNER}}"
|
||||
else
|
||||
SIGNER="${DEPLOYER_ADDRESS:-}"
|
||||
fi
|
||||
if [[ -z "${RECIPIENT}" || -z "${SIGNER}" ]]; then
|
||||
echo "Set RECIPIENT and DEPLOYER_ADDRESS or PRIVATE_KEY" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PLACEHOLDER_USED="0"
|
||||
if [[ -z "${PUBLIC_SWAP_TX_HASH_PROVIDED}" || -z "${LIQUIDITY_TX_HASH_PROVIDED}" || -z "${ISO_HASH_PROVIDED}" || -z "${AUDIT_HASH_PROVIDED}" || -z "${PEG_HASH_PROVIDED}" ]]; then
|
||||
PLACEHOLDER_USED="1"
|
||||
fi
|
||||
|
||||
if [[ "${EXECUTE}" == "1" && "${PLACEHOLDER_USED}" == "1" ]]; then
|
||||
echo "EXECUTE=1 requires PUBLIC_SWAP_TX_HASH, LIQUIDITY_TX_HASH, ISO_HASH, AUDIT_HASH, and PEG_HASH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STATE="$(cast call "${ENGINE_X_INDEXED_LIQUIDITY_VAULT}" 'currentPoolState()(uint160,int24,uint128,uint256,uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
|
||||
|
||||
cat <<EOF
|
||||
Engine X indexed proof recording plan
|
||||
mode: ${EXECUTE}
|
||||
vault: ${ENGINE_X_INDEXED_LIQUIDITY_VAULT}
|
||||
signer: ${SIGNER}
|
||||
recipient: ${RECIPIENT}
|
||||
exact output raw: ${EXACT_OUTPUT_RAW}
|
||||
proof id: ${PROOF_ID}
|
||||
public swap tx hash: ${PUBLIC_SWAP_TX_HASH}
|
||||
liquidity tx hash: ${LIQUIDITY_TX_HASH}
|
||||
iso hash: ${ISO_HASH}
|
||||
audit hash: ${AUDIT_HASH}
|
||||
peg hash: ${PEG_HASH}
|
||||
current pool state: ${STATE}
|
||||
placeholder inputs used: ${PLACEHOLDER_USED}
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. Use real tx/proof hashes before broadcasting:
|
||||
cast send "${ENGINE_X_INDEXED_LIQUIDITY_VAULT}" 'recordIndexedProof((bytes32,bytes32,bytes32,address,uint256,bytes32,bytes32,bytes32))' "(${PROOF_ID},${PUBLIC_SWAP_TX_HASH},${LIQUIDITY_TX_HASH},${RECIPIENT},${EXACT_OUTPUT_RAW},${ISO_HASH},${AUDIT_HASH},${PEG_HASH})" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cast send "${ENGINE_X_INDEXED_LIQUIDITY_VAULT}" \
|
||||
'recordIndexedProof((bytes32,bytes32,bytes32,address,uint256,bytes32,bytes32,bytes32))' \
|
||||
"(${PROOF_ID},${PUBLIC_SWAP_TX_HASH},${LIQUIDITY_TX_HASH},${RECIPIENT},${EXACT_OUTPUT_RAW},${ISO_HASH},${AUDIT_HASH},${PEG_HASH})" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
155
scripts/deployment/repair-mainnet-cwusdc-usdc-univ2-canary.sh
Executable file
155
scripts/deployment/repair-mainnet-cwusdc-usdc-univ2-canary.sh
Executable file
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
: "${PRIVATE_KEY:?PRIVATE_KEY is required}"
|
||||
|
||||
PAIR="${MAINNET_CWUSDC_USDC_UNIV2_PAIR:-0xC28706F899266b36BC43cc072b3a921BDf2C48D9}"
|
||||
ROUTER="${CHAIN_1_UNISWAP_V2_ROUTER:-0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D}"
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
SLIPPAGE_BPS="${SLIPPAGE_BPS:-100}"
|
||||
USDC_KEEP_RAW="${MAINNET_PUBLIC_LP_USDC_KEEP_RAW:-10000}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
|
||||
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
TOKEN0="$(cast call "${PAIR}" 'token0()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
|
||||
TOKEN1="$(cast call "${PAIR}" 'token1()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
|
||||
RESERVES="$(cast call "${PAIR}" 'getReserves()(uint112,uint112,uint32)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
|
||||
WALLET_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | sed -E 's/[[:space:]].*$//')"
|
||||
WALLET_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | sed -E 's/[[:space:]].*$//')"
|
||||
|
||||
PLAN="$(
|
||||
python3 - "${CWUSDC}" "${USDC}" "${TOKEN0}" "${TOKEN1}" "${RESERVES}" "${WALLET_USDC_RAW}" "${WALLET_CWUSDC_RAW}" "${SLIPPAGE_BPS}" "${USDC_KEEP_RAW}" <<'PY'
|
||||
from decimal import Decimal, ROUND_FLOOR, ROUND_CEILING, getcontext
|
||||
import re
|
||||
import sys
|
||||
|
||||
getcontext().prec = 80
|
||||
cwusdc, usdc, token0, token1, reserves, wallet_usdc, wallet_cwusdc, slippage_bps, usdc_keep = sys.argv[1:]
|
||||
# Cast prints reserves as one uint112 per line; ignore bracket scientific notation.
|
||||
_lines = [ln.strip() for ln in reserves.strip().splitlines() if ln.strip()]
|
||||
_nums = []
|
||||
for ln in _lines:
|
||||
m = re.match(r"^(\d+)", ln)
|
||||
if m:
|
||||
_nums.append(int(m.group(1)))
|
||||
if len(_nums) < 2:
|
||||
raise SystemExit("could not parse pair reserves")
|
||||
|
||||
reserve0, reserve1 = _nums[:2]
|
||||
if token0.lower() == cwusdc.lower() and token1.lower() == usdc.lower():
|
||||
base_raw, quote_raw = reserve0, reserve1
|
||||
elif token1.lower() == cwusdc.lower() and token0.lower() == usdc.lower():
|
||||
base_raw, quote_raw = reserve1, reserve0
|
||||
else:
|
||||
raise SystemExit("pair tokens do not match cWUSDC/USDC")
|
||||
|
||||
wallet_usdc_raw = int(wallet_usdc)
|
||||
wallet_cwusdc_raw = int(wallet_cwusdc)
|
||||
slippage = int(slippage_bps)
|
||||
keep_raw = int(usdc_keep)
|
||||
fee = Decimal("0.997")
|
||||
x = Decimal(base_raw)
|
||||
y = Decimal(quote_raw)
|
||||
|
||||
if y <= 0 or x <= y:
|
||||
raise SystemExit("pair does not look quote-side short; aborting canary repair")
|
||||
|
||||
# Solve for quote-in q such that post-swap reserves are equal:
|
||||
# (y + q) * (y + 0.997q) = x * y
|
||||
a = fee
|
||||
b = y * (Decimal(1) + fee)
|
||||
c = y * y - x * y
|
||||
q = (-b + (b * b - Decimal(4) * a * c).sqrt()) / (Decimal(2) * a)
|
||||
quote_in_raw = int(q.to_integral_value(rounding=ROUND_CEILING))
|
||||
quote_in_fee = Decimal(quote_in_raw) * fee
|
||||
base_out = x * quote_in_fee / (y + quote_in_fee)
|
||||
min_base_out_raw = int((base_out * Decimal(10000 - slippage) / Decimal(10000)).to_integral_value(rounding=ROUND_FLOOR))
|
||||
|
||||
if wallet_usdc_raw < quote_in_raw + keep_raw:
|
||||
raise SystemExit(
|
||||
f"insufficient USDC for canary plus keep reserve: need {quote_in_raw + keep_raw}, have {wallet_usdc_raw}"
|
||||
)
|
||||
|
||||
balanced_quote_add_raw = max(wallet_usdc_raw - quote_in_raw - keep_raw, 0)
|
||||
balanced_base_add_raw = min(wallet_cwusdc_raw + int(base_out), balanced_quote_add_raw)
|
||||
min_balanced_raw = int((Decimal(balanced_base_add_raw) * Decimal(10000 - slippage) / Decimal(10000)).to_integral_value(rounding=ROUND_FLOOR))
|
||||
|
||||
def emit(name, value):
|
||||
print(f"{name}='{value}'")
|
||||
|
||||
emit("BASE_RESERVE_RAW", base_raw)
|
||||
emit("QUOTE_RESERVE_RAW", quote_raw)
|
||||
emit("QUOTE_IN_RAW", quote_in_raw)
|
||||
emit("EXPECTED_BASE_OUT_RAW", int(base_out.to_integral_value(rounding=ROUND_FLOOR)))
|
||||
emit("MIN_BASE_OUT_RAW", min_base_out_raw)
|
||||
emit("BALANCED_ADD_RAW", balanced_base_add_raw)
|
||||
emit("MIN_BALANCED_ADD_RAW", min_balanced_raw)
|
||||
emit("USDC_KEEP_RAW_EFFECTIVE", keep_raw)
|
||||
PY
|
||||
)" || { echo "Canary planner failed (likely insufficient USDC vs computed quote-in)." >&2; exit 1; }
|
||||
eval "${PLAN}"
|
||||
|
||||
# UniV2 router is source of truth for swap output; CP closed-form above can diverge on extreme reserves.
|
||||
ROUTER_AMOUNTS="$(cast call "${ROUTER}" "getAmountsOut(uint256,address[])(uint256[])" "${QUOTE_IN_RAW}" "[${USDC},${CWUSDC}]" --rpc-url "${ETHEREUM_MAINNET_RPC}")"
|
||||
# Second hop amount is the cWUSDC out; require wide digits so we do not confuse brackets with reserves.
|
||||
EXPECTED_BASE_OUT_RAW="$(python3 -c 'import re,sys; s=sys.argv[1]; nums=[int(x) for x in re.findall(r"\b\d{10,}\b", s)]; print(nums[-1] if nums else 0)' "${ROUTER_AMOUNTS}")"
|
||||
MIN_BASE_OUT_RAW=$(( EXPECTED_BASE_OUT_RAW * (10000 - SLIPPAGE_BPS) / 10000 ))
|
||||
if [[ "${EXPECTED_BASE_OUT_RAW}" -eq 0 ]]; then
|
||||
echo "router getAmountsOut returned 0; aborting" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
Mainnet cWUSDC/USDC UniV2 public canary plan
|
||||
mode: ${EXECUTE}
|
||||
pair: ${PAIR}
|
||||
signer: ${SIGNER}
|
||||
reserves raw before: ${BASE_RESERVE_RAW} cWUSDC / ${QUOTE_RESERVE_RAW} USDC
|
||||
quote repair swap: ${QUOTE_IN_RAW} USDC raw
|
||||
expected cWUSDC out (router): ${EXPECTED_BASE_OUT_RAW} raw
|
||||
min cWUSDC out (${SLIPPAGE_BPS} bps slip): ${MIN_BASE_OUT_RAW} raw
|
||||
balanced add after repair: ${BALANCED_ADD_RAW} raw per side
|
||||
USDC keep reserve: ${USDC_KEEP_RAW_EFFECTIVE} raw
|
||||
|
||||
This is a tiny public LP canary, not policy-floor liquidity.
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. To broadcast after reviewing the numbers:
|
||||
EXECUTE=1 bash scripts/deployment/repair-mainnet-cwusdc-usdc-univ2-canary.sh
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
DEADLINE="$(( $(date +%s) + 1800 ))"
|
||||
|
||||
cast send "${USDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${QUOTE_IN_RAW}" \
|
||||
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
|
||||
cast send "${ROUTER}" 'swapExactTokensForTokens(uint256,uint256,address[],address,uint256)' \
|
||||
"${QUOTE_IN_RAW}" "${MIN_BASE_OUT_RAW}" "[${USDC},${CWUSDC}]" "${SIGNER}" "${DEADLINE}" \
|
||||
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
|
||||
if [[ "${BALANCED_ADD_RAW}" != "0" ]]; then
|
||||
cast send "${CWUSDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${BALANCED_ADD_RAW}" \
|
||||
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
cast send "${USDC}" 'approve(address,uint256)(bool)' "${ROUTER}" "${BALANCED_ADD_RAW}" \
|
||||
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
cast send "${ROUTER}" 'addLiquidity(address,address,uint256,uint256,uint256,uint256,address,uint256)' \
|
||||
"${CWUSDC}" "${USDC}" "${BALANCED_ADD_RAW}" "${BALANCED_ADD_RAW}" \
|
||||
"${MIN_BALANCED_ADD_RAW}" "${MIN_BALANCED_ADD_RAW}" "${SIGNER}" "${DEADLINE}" \
|
||||
--private-key "${PRIVATE_KEY}" --rpc-url "${ETHEREUM_MAINNET_RPC}"
|
||||
fi
|
||||
|
||||
bash "${PROJECT_ROOT}/scripts/verify/snapshot-mainnet-cwusdc-usdc-preflight.sh"
|
||||
bash "${PROJECT_ROOT}/scripts/verify/plan-mainnet-cwusdc-usdc-repeg.sh"
|
||||
124
scripts/deployment/retire-engine-x-legacy-vault.sh
Executable file
124
scripts/deployment/retire-engine-x-legacy-vault.sh
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
VAULT="${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}"
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
RECIPIENT="${RETIRE_RECIPIENT:-${DEPLOYER_ADDRESS:-}}"
|
||||
ALLOW_STALE_ACCOUNTING_RETIREMENT="${ALLOW_STALE_ACCOUNTING_RETIREMENT:-0}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
RECIPIENT="${RETIRE_RECIPIENT:-${SIGNER}}"
|
||||
else
|
||||
SIGNER="${DEPLOYER_ADDRESS:-}"
|
||||
fi
|
||||
|
||||
if [[ -z "${RECIPIENT}" ]]; then
|
||||
echo "Set RETIRE_RECIPIENT or DEPLOYER_ADDRESS" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OWNER="$(cast call "${VAULT}" 'owner()(address)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
|
||||
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}' || echo 0)"
|
||||
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}' || echo 0)"
|
||||
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}' || echo 0)"
|
||||
VAULT_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
VAULT_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
|
||||
ACCOUNTING_AWARE_SUPPORTED="0"
|
||||
if cast call "${VAULT}" 'maxFlashLoan(address)(uint256)' "${USDC}" --rpc-url "${ETHEREUM_MAINNET_RPC}" >/dev/null 2>&1; then
|
||||
ACCOUNTING_AWARE_SUPPORTED="1"
|
||||
fi
|
||||
|
||||
if [[ "${EXECUTE}" == "1" && "${SIGNER,,}" != "${OWNER,,}" ]]; then
|
||||
echo "EXECUTE=1 signer must be the vault owner" >&2
|
||||
echo " signer: ${SIGNER}" >&2
|
||||
echo " owner: ${OWNER}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
eval "$(
|
||||
python3 - "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" "${LENDER_USDC_RAW}" "${VAULT_CWUSDC_RAW}" "${VAULT_USDC_RAW}" <<'PY'
|
||||
from decimal import Decimal
|
||||
import sys
|
||||
|
||||
pool_cw, pool_usdc, lender_usdc, vault_cw, vault_usdc = map(int, sys.argv[1:])
|
||||
|
||||
def units(raw):
|
||||
return f"{Decimal(raw) / Decimal(10**6):f}"
|
||||
|
||||
def emit(k, v):
|
||||
print(f"{k}='{v}'")
|
||||
|
||||
emit("POOL_CWUSDC_UNITS", units(pool_cw))
|
||||
emit("POOL_USDC_UNITS", units(pool_usdc))
|
||||
emit("LENDER_USDC_UNITS", units(lender_usdc))
|
||||
emit("VAULT_CWUSDC_UNITS", units(vault_cw))
|
||||
emit("VAULT_USDC_UNITS", units(vault_usdc))
|
||||
emit("BALANCED_POOL_WITHDRAW_RAW", min(pool_cw, pool_usdc, vault_cw, max(vault_usdc - lender_usdc, 0)))
|
||||
PY
|
||||
)"
|
||||
|
||||
cat <<EOF
|
||||
Engine X legacy vault retirement plan
|
||||
mode: ${EXECUTE}
|
||||
vault: ${VAULT}
|
||||
owner: ${OWNER}
|
||||
signer: ${SIGNER:-n/a}
|
||||
recipient: ${RECIPIENT}
|
||||
accounting-aware API: ${ACCOUNTING_AWARE_SUPPORTED}
|
||||
accounted pool: ${POOL_CWUSDC_UNITS} cWUSDC / ${POOL_USDC_UNITS} USDC
|
||||
lender bucket: ${LENDER_USDC_UNITS} USDC
|
||||
actual balances: ${VAULT_CWUSDC_UNITS} cWUSDC / ${VAULT_USDC_UNITS} USDC
|
||||
EOF
|
||||
|
||||
if [[ "${ACCOUNTING_AWARE_SUPPORTED}" == "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Accounting-aware retirement commands:
|
||||
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${RECIPIENT}" "${BALANCED_POOL_WITHDRAW_RAW}" "${BALANCED_POOL_WITHDRAW_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${VAULT}" 'withdrawLenderUsdc(address,uint256)' "${RECIPIENT}" "${LENDER_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
EOF
|
||||
if [[ "${EXECUTE}" == "1" ]]; then
|
||||
cast send "${VAULT}" 'withdrawPoolLiquidity(address,uint256,uint256)' "${RECIPIENT}" "${BALANCED_POOL_WITHDRAW_RAW}" "${BALANCED_POOL_WITHDRAW_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${VAULT}" 'withdrawLenderUsdc(address,uint256)' "${RECIPIENT}" "${LENDER_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
|
||||
This vault does not expose accounting-aware retirement APIs. Default behavior is report-only.
|
||||
Set ALLOW_STALE_ACCOUNTING_RETIREMENT=1 only when the vault is being permanently retired
|
||||
and no future proof will rely on its internal accounting.
|
||||
EOF
|
||||
|
||||
if [[ "${ALLOW_STALE_ACCOUNTING_RETIREMENT}" != "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Legacy full-token retirement commands:
|
||||
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${CWUSDC}" "${RECIPIENT}" "${VAULT_CWUSDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${USDC}" "${RECIPIENT}" "${VAULT_USDC_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" == "1" ]]; then
|
||||
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${CWUSDC}" "${RECIPIENT}" "${VAULT_CWUSDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${VAULT}" 'withdraw(address,address,uint256)' "${USDC}" "${RECIPIENT}" "${VAULT_USDC_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
fi
|
||||
269
scripts/deployment/run-engine-x-loop-proof.sh
Executable file
269
scripts/deployment/run-engine-x-loop-proof.sh
Executable file
@@ -0,0 +1,269 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
VAULT="${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}"
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
XAUT="${XAUT_MAINNET:-0x68749665FF8D2d112Fa859AA293F07A622782F38}"
|
||||
LOOPS="${LOOPS:-1}"
|
||||
EXACT_OUTPUT_PER_LOOP_RAW="${EXACT_OUTPUT_PER_LOOP_RAW:-10000}"
|
||||
DEBT_RAW="${DEBT_RAW:-}"
|
||||
ROUNDING_RECEIVER="${ROUNDING_RECEIVER:-}"
|
||||
RECIPIENT="${RECIPIENT:-}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
STAMP="${ENGINE_X_LOOP_PROOF_STAMP:-$(date -u +%Y%m%dT%H%M%SZ)}"
|
||||
OUT_JSON="${OUT_JSON:-reports/status/engine-x-loop-proof-${STAMP}.json}"
|
||||
OUT_MD="${OUT_MD:-reports/status/engine-x-loop-proof-${STAMP}.md}"
|
||||
LATEST_JSON="${LATEST_JSON:-reports/status/engine-x-loop-proof-latest.json}"
|
||||
LATEST_MD="${LATEST_MD:-reports/status/engine-x-loop-proof-latest.md}"
|
||||
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
else
|
||||
SIGNER="${DEPLOYER_ADDRESS:-}"
|
||||
fi
|
||||
if [[ -z "${SIGNER}" ]]; then
|
||||
echo "Set PRIVATE_KEY or DEPLOYER_ADDRESS" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RECIPIENT="${RECIPIENT:-${SIGNER}}"
|
||||
ROUNDING_RECEIVER="${ROUNDING_RECEIVER:-${SIGNER}}"
|
||||
PROOF_ID="${PROOF_ID:-$(cast keccak "dbis-engine-x:loop-proof:${SIGNER}:${RECIPIENT}:${EXACT_OUTPUT_PER_LOOP_RAW}:${LOOPS}:${STAMP}")}"
|
||||
ISO_HASH="${ISO_HASH:-$(cast keccak "dbis-engine-x:loop-proof:iso:${PROOF_ID}")}"
|
||||
AUDIT_HASH="${AUDIT_HASH:-$(cast keccak "dbis-engine-x:loop-proof:audit:${PROOF_ID}")}"
|
||||
PEG_HASH="${PEG_HASH:-$(cast keccak "dbis-engine-x:loop-proof:peg:${PROOF_ID}")}"
|
||||
|
||||
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
|
||||
if [[ -z "${DEBT_RAW}" ]]; then
|
||||
DEBT_RAW="$(
|
||||
python3 - "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" "${EXACT_OUTPUT_PER_LOOP_RAW}" "${LENDER_USDC_RAW}" <<'PY'
|
||||
import sys
|
||||
|
||||
reserve_cw = int(sys.argv[1])
|
||||
reserve_usdc = int(sys.argv[2])
|
||||
target = int(sys.argv[3])
|
||||
max_debt = int(sys.argv[4])
|
||||
|
||||
def amount_in(amount_out, reserve_in, reserve_out):
|
||||
if amount_out <= 0 or reserve_in <= 0 or reserve_out <= amount_out:
|
||||
raise ValueError("bad getAmountIn inputs")
|
||||
return reserve_in * amount_out * 1000 // ((reserve_out - amount_out) * 997) + 1
|
||||
|
||||
def amount_out(amount_in, reserve_in, reserve_out):
|
||||
if amount_in <= 0 or reserve_in <= 0 or reserve_out <= 0:
|
||||
raise ValueError("bad getAmountOut inputs")
|
||||
return amount_in * 997 * reserve_out // (reserve_in * 1000 + amount_in * 997)
|
||||
|
||||
for debt in range(1, max_debt + 1):
|
||||
cw_in = amount_in(debt, reserve_cw, reserve_usdc)
|
||||
cw_reserve_after_in = reserve_cw + cw_in
|
||||
usdc_reserve_after_out = reserve_usdc - debt
|
||||
cw_out = amount_out(debt, usdc_reserve_after_out, cw_reserve_after_in)
|
||||
if cw_out >= target:
|
||||
print(debt)
|
||||
raise SystemExit(0)
|
||||
raise SystemExit("no debt size can reach exact output within lender bucket")
|
||||
PY
|
||||
)"
|
||||
fi
|
||||
|
||||
mapfile -t PREVIEW < <(
|
||||
cast call "${VAULT}" \
|
||||
'previewVirtualProof(uint256,uint256)(uint256,uint256,uint256,uint256,uint256,uint256,uint256)' \
|
||||
"${DEBT_RAW}" "${LOOPS}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}'
|
||||
)
|
||||
|
||||
COLLATERAL_XAUT_RAW="${PREVIEW[0]}"
|
||||
CWUSDC_IN_PER_LOOP_RAW="${PREVIEW[1]}"
|
||||
CWUSDC_OUT_PER_LOOP_RAW="${PREVIEW[2]}"
|
||||
CWUSDC_LOSS_PER_LOOP_RAW="${PREVIEW[3]}"
|
||||
TOTAL_CWUSDC_IN_RAW="${PREVIEW[4]}"
|
||||
TOTAL_CWUSDC_OUT_RAW="${PREVIEW[5]}"
|
||||
TOTAL_NEUTRALIZED_RAW="${PREVIEW[6]}"
|
||||
EXACT_OUTPUT_TOTAL_RAW="$((EXACT_OUTPUT_PER_LOOP_RAW * LOOPS))"
|
||||
OUTPUT_ROUNDING_RAW="$((TOTAL_CWUSDC_OUT_RAW - EXACT_OUTPUT_TOTAL_RAW))"
|
||||
|
||||
if (( OUTPUT_ROUNDING_RAW < 0 )); then
|
||||
echo "Preview output is lower than requested exact output" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CWUSDC_BAL_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
XAUT_BAL_RAW="$(cast call "${XAUT}" 'balanceOf(address)(uint256)' "${SIGNER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
CWUSDC_ALLOWANCE_RAW="$(cast call "${CWUSDC}" 'allowance(address,address)(uint256)' "${SIGNER}" "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
XAUT_ALLOWANCE_RAW="$(cast call "${XAUT}" 'allowance(address,address)(uint256)' "${SIGNER}" "${VAULT}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
PROOF_USED="$(cast call "${VAULT}" 'usedProofIds(bytes32)(bool)' "${PROOF_ID}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | tr -d '[:space:]')"
|
||||
|
||||
if [[ "${PROOF_USED}" == "true" ]]; then
|
||||
echo "Proof ID is already used: ${PROOF_ID}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if (( CWUSDC_BAL_RAW < TOTAL_CWUSDC_IN_RAW )); then
|
||||
echo "Insufficient cWUSDC balance" >&2
|
||||
exit 1
|
||||
fi
|
||||
if (( XAUT_BAL_RAW < COLLATERAL_XAUT_RAW )); then
|
||||
echo "Insufficient XAUt balance" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CWUSDC_APPROVE_NEEDED=0
|
||||
XAUT_APPROVE_NEEDED=0
|
||||
if (( CWUSDC_ALLOWANCE_RAW < TOTAL_CWUSDC_IN_RAW )); then
|
||||
CWUSDC_APPROVE_NEEDED=1
|
||||
fi
|
||||
if (( XAUT_ALLOWANCE_RAW < COLLATERAL_XAUT_RAW )); then
|
||||
XAUT_APPROVE_NEEDED=1
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${OUT_JSON}")"
|
||||
python3 - "${OUT_JSON}" "${OUT_MD}" "${LATEST_JSON}" "${LATEST_MD}" \
|
||||
"${EXECUTE}" "${STAMP}" "${VAULT}" "${SIGNER}" "${RECIPIENT}" "${ROUNDING_RECEIVER}" \
|
||||
"${LOOPS}" "${EXACT_OUTPUT_PER_LOOP_RAW}" "${DEBT_RAW}" "${PROOF_ID}" "${ISO_HASH}" "${AUDIT_HASH}" "${PEG_HASH}" \
|
||||
"${COLLATERAL_XAUT_RAW}" "${CWUSDC_IN_PER_LOOP_RAW}" "${CWUSDC_OUT_PER_LOOP_RAW}" "${CWUSDC_LOSS_PER_LOOP_RAW}" \
|
||||
"${TOTAL_CWUSDC_IN_RAW}" "${TOTAL_CWUSDC_OUT_RAW}" "${EXACT_OUTPUT_TOTAL_RAW}" "${OUTPUT_ROUNDING_RAW}" "${TOTAL_NEUTRALIZED_RAW}" \
|
||||
"${CWUSDC_BAL_RAW}" "${XAUT_BAL_RAW}" "${CWUSDC_ALLOWANCE_RAW}" "${XAUT_ALLOWANCE_RAW}" "${CWUSDC_APPROVE_NEEDED}" "${XAUT_APPROVE_NEEDED}" <<'PY'
|
||||
from decimal import Decimal
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
(
|
||||
out_json, out_md, latest_json, latest_md, execute, stamp, vault, signer, recipient, rounding_receiver,
|
||||
loops, exact_per_loop, debt, proof_id, iso_hash, audit_hash, peg_hash, collateral, cw_in, cw_out, loss,
|
||||
total_in, total_out, exact_total, rounding, neutralized, cw_bal, xaut_bal, cw_allow, xaut_allow,
|
||||
cw_approve, xaut_approve,
|
||||
) = sys.argv[1:]
|
||||
|
||||
def units(raw):
|
||||
return f"{Decimal(int(raw)) / Decimal(10**6):f}"
|
||||
|
||||
payload = {
|
||||
"schema": "engine-x-loop-proof/v1",
|
||||
"executed": execute == "1",
|
||||
"stamp": stamp,
|
||||
"vault": vault,
|
||||
"signer": signer,
|
||||
"recipient": recipient,
|
||||
"roundingReceiver": rounding_receiver,
|
||||
"loops": int(loops),
|
||||
"debtUsdcPerLoopRaw": debt,
|
||||
"debtUsdcPerLoop": units(debt),
|
||||
"exactOutputPerLoopRaw": exact_per_loop,
|
||||
"exactOutputPerLoop": units(exact_per_loop),
|
||||
"proofId": proof_id,
|
||||
"isoHash": iso_hash,
|
||||
"auditHash": audit_hash,
|
||||
"pegHash": peg_hash,
|
||||
"preview": {
|
||||
"collateralXautRaw": collateral,
|
||||
"collateralXaut": units(collateral),
|
||||
"cwusdcInPerLoopRaw": cw_in,
|
||||
"cwusdcInPerLoop": units(cw_in),
|
||||
"cwusdcOutPerLoopRaw": cw_out,
|
||||
"cwusdcOutPerLoop": units(cw_out),
|
||||
"cwusdcLossPerLoopRaw": loss,
|
||||
"cwusdcLossPerLoop": units(loss),
|
||||
"totalCwusdcInRaw": total_in,
|
||||
"totalCwusdcIn": units(total_in),
|
||||
"totalCwusdcOutRaw": total_out,
|
||||
"totalCwusdcOut": units(total_out),
|
||||
"exactOutputTotalRaw": exact_total,
|
||||
"exactOutputTotal": units(exact_total),
|
||||
"outputRoundingRaw": rounding,
|
||||
"outputRounding": units(rounding),
|
||||
"totalNeutralizedRaw": neutralized,
|
||||
"totalNeutralized": units(neutralized),
|
||||
},
|
||||
"balances": {
|
||||
"cwusdcRaw": cw_bal,
|
||||
"cwusdc": units(cw_bal),
|
||||
"xautRaw": xaut_bal,
|
||||
"xaut": units(xaut_bal),
|
||||
"cwusdcAllowanceRaw": cw_allow,
|
||||
"xautAllowanceRaw": xaut_allow,
|
||||
"cwusdcApproveNeeded": cw_approve == "1",
|
||||
"xautApproveNeeded": xaut_approve == "1",
|
||||
},
|
||||
}
|
||||
Path(out_json).write_text(json.dumps(payload, indent=2) + "\n")
|
||||
Path(latest_json).write_text(json.dumps(payload, indent=2) + "\n")
|
||||
lines = [
|
||||
"# Engine X Loop Proof",
|
||||
"",
|
||||
f"- Executed: `{payload['executed']}`",
|
||||
f"- Vault: `{vault}`",
|
||||
f"- Loops: `{loops}`",
|
||||
f"- Exact cWUSDC output per loop: `{payload['exactOutputPerLoop']}`",
|
||||
f"- Debt USDC per loop: `{payload['debtUsdcPerLoop']}`",
|
||||
f"- cWUSDC in/out per loop: `{payload['preview']['cwusdcInPerLoop']} / {payload['preview']['cwusdcOutPerLoop']}`",
|
||||
f"- Neutralized per loop: `{payload['preview']['cwusdcLossPerLoop']}`",
|
||||
f"- Total exact output: `{payload['preview']['exactOutputTotal']}`",
|
||||
f"- Proof ID: `{proof_id}`",
|
||||
f"- cWUSDC approval needed: `{payload['balances']['cwusdcApproveNeeded']}`",
|
||||
f"- XAUt approval needed: `{payload['balances']['xautApproveNeeded']}`",
|
||||
]
|
||||
Path(out_md).write_text("\n".join(lines) + "\n")
|
||||
Path(latest_md).write_text("\n".join(lines) + "\n")
|
||||
PY
|
||||
|
||||
cat <<EOF
|
||||
Engine X loop proof plan
|
||||
mode: ${EXECUTE}
|
||||
vault: ${VAULT}
|
||||
signer: ${SIGNER}
|
||||
recipient: ${RECIPIENT}
|
||||
loops: ${LOOPS}
|
||||
exact cWUSDC output per loop raw: ${EXACT_OUTPUT_PER_LOOP_RAW}
|
||||
debt USDC per loop raw: ${DEBT_RAW}
|
||||
cWUSDC in/out/loss per loop raw: ${CWUSDC_IN_PER_LOOP_RAW} / ${CWUSDC_OUT_PER_LOOP_RAW} / ${CWUSDC_LOSS_PER_LOOP_RAW}
|
||||
total exact output raw: ${EXACT_OUTPUT_TOTAL_RAW}
|
||||
total cWUSDC input raw: ${TOTAL_CWUSDC_IN_RAW}
|
||||
total neutralized raw: ${TOTAL_NEUTRALIZED_RAW}
|
||||
XAUt collateral raw: ${COLLATERAL_XAUT_RAW}
|
||||
proof id: ${PROOF_ID}
|
||||
cWUSDC approve needed: ${CWUSDC_APPROVE_NEEDED}
|
||||
XAUt approve needed: ${XAUT_APPROVE_NEEDED}
|
||||
report: ${OUT_JSON}
|
||||
EOF
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. To broadcast this exact loop proof:
|
||||
EXECUTE=1 LOOPS=${LOOPS} EXACT_OUTPUT_PER_LOOP_RAW=${EXACT_OUTPUT_PER_LOOP_RAW} \\
|
||||
PROOF_ID=${PROOF_ID} ISO_HASH=${ISO_HASH} AUDIT_HASH=${AUDIT_HASH} PEG_HASH=${PEG_HASH} \\
|
||||
bash scripts/deployment/run-engine-x-loop-proof.sh
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${CWUSDC_APPROVE_NEEDED}" == "1" ]]; then
|
||||
cast send "${CWUSDC}" 'approve(address,uint256)' "${VAULT}" "${TOTAL_CWUSDC_IN_RAW}" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
fi
|
||||
if [[ "${XAUT_APPROVE_NEEDED}" == "1" ]]; then
|
||||
cast send "${XAUT}" 'approve(address,uint256)' "${VAULT}" "${COLLATERAL_XAUT_RAW}" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
fi
|
||||
|
||||
cast send "${VAULT}" \
|
||||
'runVirtualProofExactOutTo(bytes32,uint256,uint256,address,uint256,address,bytes32,bytes32,bytes32)' \
|
||||
"${PROOF_ID}" "${DEBT_RAW}" "${LOOPS}" "${RECIPIENT}" "${EXACT_OUTPUT_TOTAL_RAW}" "${ROUNDING_RECEIVER}" \
|
||||
"${ISO_HASH}" "${AUDIT_HASH}" "${PEG_HASH}" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
113
scripts/deployment/run-engine-x-univ3-public-swap-proof.sh
Executable file
113
scripts/deployment/run-engine-x-univ3-public-swap-proof.sh
Executable file
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
|
||||
ROUTER="${CHAIN_1_UNISWAP_V3_ROUTER:-0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45}"
|
||||
QUOTER="${CHAIN_1_UNISWAP_V3_QUOTER:-0x61fFE014bA17989E743c5F6cB21bF9697530B21e}"
|
||||
FEE="${ENGINE_X_UNIV3_FEE:-100}"
|
||||
DIRECTION="${DIRECTION:-USDC_TO_CWUSDC}"
|
||||
AMOUNT_IN_RAW="${AMOUNT_IN_RAW:-10000}"
|
||||
SLIPPAGE_BPS="${SLIPPAGE_BPS:-100}"
|
||||
DEADLINE_SECONDS="${DEADLINE_SECONDS:-600}"
|
||||
EXECUTE="${EXECUTE:-0}"
|
||||
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
SIGNER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
else
|
||||
SIGNER="${DEPLOYER_ADDRESS:-}"
|
||||
fi
|
||||
if [[ -z "${SIGNER}" ]]; then
|
||||
echo "Set PRIVATE_KEY or DEPLOYER_ADDRESS" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${EXECUTE}" == "1" && -z "${PRIVATE_KEY:-}" ]]; then
|
||||
echo "PRIVATE_KEY is required when EXECUTE=1" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "${DIRECTION}" in
|
||||
USDC_TO_CWUSDC)
|
||||
TOKEN_IN="${USDC}"
|
||||
TOKEN_OUT="${CWUSDC}"
|
||||
;;
|
||||
CWUSDC_TO_USDC)
|
||||
TOKEN_IN="${CWUSDC}"
|
||||
TOKEN_OUT="${USDC}"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported DIRECTION: ${DIRECTION}; use USDC_TO_CWUSDC or CWUSDC_TO_USDC" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
TOKEN0="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '1p')"
|
||||
TOKEN1="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '2p')"
|
||||
POOL="$(cast call "${FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" | grep -oE '0x[a-fA-F0-9]{40}' | head -1)"
|
||||
|
||||
if [[ "${POOL}" == "0x0000000000000000000000000000000000000000" ]]; then
|
||||
cat <<EOF
|
||||
Engine X UniV3 public swap proof blocked
|
||||
pool: not deployed
|
||||
fee: ${FEE}
|
||||
required first: pnpm engine-x:indexed-lp-migration against an upgraded vault
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SLOT0="$(cast call "${POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}")"
|
||||
LIQUIDITY="$(cast call "${POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}" | awk '{print $1}')"
|
||||
QUOTE_OUT_RAW="$(
|
||||
cast call "${QUOTER}" \
|
||||
'quoteExactInputSingle((address,address,uint256,uint24,uint160))(uint256,uint160,uint32,uint256)' \
|
||||
"(${TOKEN_IN},${TOKEN_OUT},${AMOUNT_IN_RAW},${FEE},0)" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || true
|
||||
)"
|
||||
QUOTE_OUT_RAW="${QUOTE_OUT_RAW:-0}"
|
||||
MIN_OUT_RAW="$((QUOTE_OUT_RAW * (10000 - SLIPPAGE_BPS) / 10000))"
|
||||
DEADLINE="$(( $(date +%s) + DEADLINE_SECONDS ))"
|
||||
|
||||
cat <<EOF
|
||||
Engine X UniV3 public swap proof plan
|
||||
mode: ${EXECUTE}
|
||||
signer: ${SIGNER}
|
||||
direction: ${DIRECTION}
|
||||
pool: ${POOL}
|
||||
fee: ${FEE}
|
||||
slot0: ${SLOT0}
|
||||
liquidity: ${LIQUIDITY}
|
||||
token in: ${TOKEN_IN}
|
||||
token out: ${TOKEN_OUT}
|
||||
amount in raw: ${AMOUNT_IN_RAW}
|
||||
quote out raw: ${QUOTE_OUT_RAW}
|
||||
min out raw: ${MIN_OUT_RAW}
|
||||
EOF
|
||||
|
||||
if [[ "${QUOTE_OUT_RAW}" == "0" ]]; then
|
||||
echo "Quote is zero or unavailable; no broadcast command emitted."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${EXECUTE}" != "1" ]]; then
|
||||
cat <<EOF
|
||||
|
||||
Dry-run only. Review commands:
|
||||
cast send "${TOKEN_IN}" 'approve(address,uint256)' "${ROUTER}" "${AMOUNT_IN_RAW}" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
cast send "${ROUTER}" 'exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))(uint256)' "(${TOKEN_IN},${TOKEN_OUT},${FEE},${SIGNER},${DEADLINE},${AMOUNT_IN_RAW},${MIN_OUT_RAW},0)" --rpc-url "\$ETHEREUM_MAINNET_RPC" --private-key "\$PRIVATE_KEY"
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cast send "${TOKEN_IN}" 'approve(address,uint256)' "${ROUTER}" "${AMOUNT_IN_RAW}" --rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
cast send "${ROUTER}" 'exactInputSingle((address,address,uint24,address,uint256,uint256,uint256,uint160))(uint256)' \
|
||||
"(${TOKEN_IN},${TOKEN_OUT},${FEE},${SIGNER},${DEADLINE},${AMOUNT_IN_RAW},${MIN_OUT_RAW},0)" \
|
||||
--rpc-url "${ETHEREUM_MAINNET_RPC}" --private-key "${PRIVATE_KEY}"
|
||||
@@ -85,7 +85,7 @@ _lpr_export_from_private_key
|
||||
# 4b. Strip trailing CR/LF from RPC URL vars (editor mistakes; breaks cast/curl)
|
||||
for _lpr_k in RPC_URL_138 RPC_URL CHAIN138_RPC CHAIN138_RPC_URL CHAIN_138_RPC_URL \
|
||||
TOKEN_AGG_CHAIN138_RPC_URL TOKEN_AGGREGATION_CHAIN138_RPC_URL TOKEN_AGGREGATION_PMM_RPC_URL \
|
||||
ETHEREUM_MAINNET_RPC \
|
||||
INFURA_PROJECT_ID INFURA_API_KEY INFURA_PROJECT_SECRET ETHEREUM_MAINNET_RPC ETH_MAINNET_RPC_URL \
|
||||
XDC_PARENTNET_URL PARENTNET_URL SUBNET_URL XDC_ZERO_PEER_RPC_URL \
|
||||
RPC_URL_138_PUBLIC GNOSIS_MAINNET_RPC GNOSIS_RPC CRONOS_RPC_URL CRONOS_RPC \
|
||||
CELO_MAINNET_RPC CELO_RPC WEMIX_RPC WEMIX_MAINNET_RPC BSC_RPC_URL \
|
||||
@@ -110,6 +110,27 @@ for _lpr_id in 1 10 25 56 100 137 138 1111 8453 42161 42220 43114 651940; do
|
||||
done
|
||||
unset _lpr_k _lpr_v _lpr_id 2>/dev/null || true
|
||||
|
||||
# 4d. Ethereum RPC alias (dotenv often sets ETH_MAINNET_RPC_URL only)
|
||||
export ETHEREUM_MAINNET_RPC="${ETHEREUM_MAINNET_RPC:-${ETH_MAINNET_RPC_URL:-}}"
|
||||
export RPC_URL_MAINNET="${RPC_URL_MAINNET:-${ETHEREUM_MAINNET_RPC:-}}"
|
||||
|
||||
# 4e. Optional Infura: when INFURA_PROJECT_ID or INFURA_API_KEY is set, fill unset public-chain RPCs
|
||||
# (Infura dashboard labels this value "API Key"; JSON-RPC path is always .../v3/<that_value>.)
|
||||
_lpr_inf="${INFURA_PROJECT_ID:-${INFURA_API_KEY:-}}"
|
||||
if [[ -n "$_lpr_inf" ]]; then
|
||||
[[ -z "${ETHEREUM_MAINNET_RPC:-}" ]] && export ETHEREUM_MAINNET_RPC="https://mainnet.infura.io/v3/${_lpr_inf}"
|
||||
export RPC_URL_MAINNET="${RPC_URL_MAINNET:-${ETHEREUM_MAINNET_RPC:-}}"
|
||||
[[ -z "${POLYGON_MAINNET_RPC:-}" ]] && [[ -z "${POLYGON_RPC_URL:-}" ]] && export POLYGON_MAINNET_RPC="https://polygon-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
[[ -z "${ARBITRUM_MAINNET_RPC:-}" ]] && [[ -z "${ARBITRUM_RPC_URL:-}" ]] && export ARBITRUM_MAINNET_RPC="https://arbitrum-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
[[ -z "${OPTIMISM_MAINNET_RPC:-}" ]] && [[ -z "${OPTIMISM_RPC_URL:-}" ]] && export OPTIMISM_MAINNET_RPC="https://optimism-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
[[ -z "${BASE_MAINNET_RPC:-}" ]] && [[ -z "${BASE_RPC_URL:-}" ]] && export BASE_MAINNET_RPC="https://base-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
[[ -z "${AVALANCHE_MAINNET_RPC:-}" ]] && [[ -z "${AVALANCHE_RPC_URL:-}" ]] && export AVALANCHE_MAINNET_RPC="https://avalanche-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
[[ -z "${BSC_RPC_URL:-}" ]] && [[ -z "${BSC_MAINNET_RPC:-}" ]] && export BSC_RPC_URL="https://bnb-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
[[ -z "${GNOSIS_MAINNET_RPC:-}" ]] && [[ -z "${GNOSIS_RPC_URL:-}" ]] && [[ -z "${GNOSIS_RPC:-}" ]] && export GNOSIS_MAINNET_RPC="https://gnosis-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
[[ -z "${CELO_MAINNET_RPC:-}" ]] && [[ -z "${CELO_RPC_URL:-}" ]] && [[ -z "${CELO_RPC:-}" ]] && export CELO_MAINNET_RPC="https://celo-mainnet.infura.io/v3/${_lpr_inf}"
|
||||
fi
|
||||
unset _lpr_inf
|
||||
|
||||
# 5. Contract addresses from master JSON (config/smart-contracts-master.json) when not set by .env
|
||||
[[ -f "${PROJECT_ROOT}/scripts/lib/load-contract-addresses.sh" ]] && source "${PROJECT_ROOT}/scripts/lib/load-contract-addresses.sh" 2>/dev/null || true
|
||||
|
||||
|
||||
128
scripts/verify/build-engine-x-audit-manifest.sh
Executable file
128
scripts/verify/build-engine-x-audit-manifest.sh
Executable file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
OUT_DIR="${OUT_DIR:-reports/status}"
|
||||
MANIFEST_JSON="${MANIFEST_JSON:-${OUT_DIR}/engine-x-audit-manifest-latest.json}"
|
||||
MANIFEST_MD="${MANIFEST_MD:-${OUT_DIR}/engine-x-audit-manifest-latest.md}"
|
||||
mkdir -p "${PROJECT_ROOT}/${OUT_DIR}"
|
||||
|
||||
V2_ABI="${OUT_DIR}/engine-x-v2-vault-abi-latest.json"
|
||||
INDEXED_ABI="${OUT_DIR}/engine-x-indexed-liquidity-vault-abi-latest.json"
|
||||
BORROWER_ABI="${OUT_DIR}/engine-x-flash-proof-borrower-abi-latest.json"
|
||||
|
||||
pushd "${PROJECT_ROOT}/smom-dbis-138" >/dev/null
|
||||
forge inspect contracts/flash/DBISEngineXVirtualBatchVault.sol:DBISEngineXVirtualBatchVault abi >"${PROJECT_ROOT}/${V2_ABI}"
|
||||
forge inspect contracts/flash/DBISEngineXIndexedLiquidityVault.sol:DBISEngineXIndexedLiquidityVault abi >"${PROJECT_ROOT}/${INDEXED_ABI}"
|
||||
forge inspect contracts/flash/DBISEngineXFlashProofBorrower.sol:DBISEngineXFlashProofBorrower abi >"${PROJECT_ROOT}/${BORROWER_ABI}"
|
||||
popd >/dev/null
|
||||
|
||||
python3 - "${PROJECT_ROOT}" "${MANIFEST_JSON}" "${MANIFEST_MD}" "${V2_ABI}" "${INDEXED_ABI}" "${BORROWER_ABI}" <<'PY'
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
root = Path(sys.argv[1])
|
||||
manifest_json = root / sys.argv[2]
|
||||
manifest_md = root / sys.argv[3]
|
||||
abi_paths = [Path(p) for p in sys.argv[4:]]
|
||||
|
||||
def sha256(path: Path) -> str:
|
||||
return "0x" + hashlib.sha256((root / path).read_bytes()).hexdigest()
|
||||
|
||||
contracts = [
|
||||
{
|
||||
"name": "DBISEngineXVirtualBatchVault",
|
||||
"source": "smom-dbis-138/contracts/flash/DBISEngineXVirtualBatchVault.sol",
|
||||
"abi": str(abi_paths[0]),
|
||||
"abiSha256": sha256(abi_paths[0]),
|
||||
"constructorArgs": [
|
||||
"cWUSDC",
|
||||
"USDC",
|
||||
"XAUt",
|
||||
"owner",
|
||||
"surplusReceiver",
|
||||
"xautUsdPrice6",
|
||||
"ltvBps",
|
||||
"maxRoundTripLossBps",
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "DBISEngineXIndexedLiquidityVault",
|
||||
"source": "smom-dbis-138/contracts/flash/DBISEngineXIndexedLiquidityVault.sol",
|
||||
"abi": str(abi_paths[1]),
|
||||
"abiSha256": sha256(abi_paths[1]),
|
||||
"constructorArgs": [
|
||||
"cWUSDC",
|
||||
"USDC",
|
||||
"uniV3Pool",
|
||||
"owner",
|
||||
"maxAbsTick",
|
||||
"minLiquidity",
|
||||
"maxProofSwapAmount",
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "DBISEngineXFlashProofBorrower",
|
||||
"source": "smom-dbis-138/contracts/flash/DBISEngineXFlashProofBorrower.sol",
|
||||
"abi": str(abi_paths[2]),
|
||||
"abiSha256": sha256(abi_paths[2]),
|
||||
"constructorArgs": ["lender", "USDC", "owner"],
|
||||
},
|
||||
]
|
||||
|
||||
payload = {
|
||||
"schema": "engine-x-audit-manifest/v1",
|
||||
"generatedAt": datetime.now(timezone.utc).isoformat(),
|
||||
"contracts": contracts,
|
||||
"operatorScripts": [
|
||||
"scripts/deployment/deploy-engine-x-v2-mainnet.sh",
|
||||
"scripts/deployment/migrate-engine-x-vault-to-mainnet-cwusdc-usdc-univ3.sh",
|
||||
"scripts/deployment/deploy-engine-x-indexed-liquidity-vault-mainnet.sh",
|
||||
"scripts/deployment/run-engine-x-univ3-public-swap-proof.sh",
|
||||
"scripts/deployment/record-engine-x-indexed-liquidity-proof.sh",
|
||||
"scripts/deployment/retire-engine-x-legacy-vault.sh",
|
||||
"scripts/verify/check-engine-x-public-indexed-readiness.sh",
|
||||
],
|
||||
"reports": [
|
||||
"reports/status/mainnet-engine-x-indexed-liquidity-upgrade-plan-20260507.md",
|
||||
"reports/status/mainnet-cwusdc-cross-protocol-public-lp-proof-plan-20260507.md",
|
||||
"reports/status/engine-x-public-indexed-readiness-latest.json",
|
||||
],
|
||||
"proofRequirements": [
|
||||
"verified deployed source",
|
||||
"constructor args",
|
||||
"public UniV3 liquidity tx hash",
|
||||
"actual public cWUSDC/USDC swap tx hash",
|
||||
"pre/post pool slot0 and liquidity",
|
||||
"ISO 20022-style hash",
|
||||
"audit envelope hash",
|
||||
"peg proof hash",
|
||||
],
|
||||
}
|
||||
|
||||
manifest_json.write_text(json.dumps(payload, indent=2) + "\n")
|
||||
lines = [
|
||||
"# Engine X Audit Manifest",
|
||||
"",
|
||||
f"- Generated: `{payload['generatedAt']}`",
|
||||
"",
|
||||
"## Contracts",
|
||||
]
|
||||
for c in contracts:
|
||||
lines.append(f"- `{c['name']}`: `{c['source']}` ABI `{c['abi']}` hash `{c['abiSha256']}`")
|
||||
lines.extend(["", "## Operator Scripts"])
|
||||
lines.extend(f"- `{s}`" for s in payload["operatorScripts"])
|
||||
lines.extend(["", "## Proof Requirements"])
|
||||
lines.extend(f"- {r}" for r in payload["proofRequirements"])
|
||||
manifest_md.write_text("\n".join(lines) + "\n")
|
||||
print(manifest_json)
|
||||
print(manifest_md)
|
||||
PY
|
||||
169
scripts/verify/check-engine-x-public-indexed-readiness.sh
Executable file
169
scripts/verify/check-engine-x-public-indexed-readiness.sh
Executable file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||
|
||||
# shellcheck source=/home/intlc/projects/proxmox/scripts/lib/load-project-env.sh
|
||||
source "${PROJECT_ROOT}/scripts/lib/load-project-env.sh"
|
||||
|
||||
: "${ETHEREUM_MAINNET_RPC:?ETHEREUM_MAINNET_RPC is required}"
|
||||
|
||||
OUT_JSON="${OUT_JSON:-reports/status/engine-x-public-indexed-readiness-latest.json}"
|
||||
OUT_MD="${OUT_MD:-reports/status/engine-x-public-indexed-readiness-latest.md}"
|
||||
CWUSDC="${CWUSDC_MAINNET:-0x2de5F116bFcE3d0f922d9C8351e0c5Fc24b9284a}"
|
||||
USDC="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
|
||||
V2_PAIR="${MAINNET_CWUSDC_USDC_UNIV2_PAIR:-0xC28706F899266b36BC43cc072b3a921BDf2C48D9}"
|
||||
V3_FACTORY="${CHAIN_1_UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
|
||||
V3_FEE="${ENGINE_X_UNIV3_FEE:-100}"
|
||||
VAULT="${DBIS_ENGINE_X_V2_VAULT:-${ENGINE_X_VAULT:-0x9a22a3e272A364D64240dE6bda796FcA421cA7E9}}"
|
||||
INDEXED_VAULT="${ENGINE_X_INDEXED_LIQUIDITY_VAULT:-}"
|
||||
|
||||
if [[ -n "${PRIVATE_KEY:-}" ]]; then
|
||||
DEPLOYER="$(cast wallet address --private-key "${PRIVATE_KEY}")"
|
||||
else
|
||||
DEPLOYER="${DEPLOYER_ADDRESS:-}"
|
||||
fi
|
||||
|
||||
TOKEN0="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '1p')"
|
||||
TOKEN1="$(printf '%s\n%s\n' "${CWUSDC}" "${USDC}" | tr '[:upper:]' '[:lower:]' | sort | sed -n '2p')"
|
||||
V3_POOL="$(cast call "${V3_FACTORY}" 'getPool(address,address,uint24)(address)' "${TOKEN0}" "${TOKEN1}" "${V3_FEE}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | grep -oE '0x[a-fA-F0-9]{40}' | head -1 || true)"
|
||||
V3_POOL="${V3_POOL:-0x0000000000000000000000000000000000000000}"
|
||||
|
||||
ACCOUNTING_AWARE="0"
|
||||
cast call "${VAULT}" 'maxFlashLoan(address)(uint256)' "${USDC}" --rpc-url "${ETHEREUM_MAINNET_RPC}" >/dev/null 2>&1 && ACCOUNTING_AWARE="1"
|
||||
|
||||
POOL_CWUSDC_RAW="$(cast call "${VAULT}" 'poolCwusdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
POOL_USDC_RAW="$(cast call "${VAULT}" 'poolUsdcReserve()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
LENDER_USDC_RAW="$(cast call "${VAULT}" 'lenderUsdcAvailable()(uint256)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
V2_RESERVES="$(cast call "${V2_PAIR}" 'getReserves()(uint112,uint112,uint32)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null || true)"
|
||||
V3_SLOT0=""
|
||||
V3_LIQUIDITY="0"
|
||||
V3_TOKEN0_BALANCE="0"
|
||||
V3_TOKEN1_BALANCE="0"
|
||||
if [[ "${V3_POOL}" != "0x0000000000000000000000000000000000000000" ]]; then
|
||||
V3_SLOT0="$(cast call "${V3_POOL}" 'slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null || true)"
|
||||
V3_LIQUIDITY="$(cast call "${V3_POOL}" 'liquidity()(uint128)' --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
V3_TOKEN0_BALANCE="$(cast call "${TOKEN0}" 'balanceOf(address)(uint256)' "${V3_POOL}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
V3_TOKEN1_BALANCE="$(cast call "${TOKEN1}" 'balanceOf(address)(uint256)' "${V3_POOL}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
fi
|
||||
WALLET_CWUSDC_RAW="0"
|
||||
WALLET_USDC_RAW="0"
|
||||
if [[ -n "${DEPLOYER}" ]]; then
|
||||
WALLET_CWUSDC_RAW="$(cast call "${CWUSDC}" 'balanceOf(address)(uint256)' "${DEPLOYER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
WALLET_USDC_RAW="$(cast call "${USDC}" 'balanceOf(address)(uint256)' "${DEPLOYER}" --rpc-url "${ETHEREUM_MAINNET_RPC}" 2>/dev/null | awk '{print $1}' || echo 0)"
|
||||
fi
|
||||
|
||||
mkdir -p "$(dirname "${OUT_JSON}")"
|
||||
python3 - "${OUT_JSON}" "${OUT_MD}" \
|
||||
"${VAULT}" "${ACCOUNTING_AWARE}" "${POOL_CWUSDC_RAW}" "${POOL_USDC_RAW}" "${LENDER_USDC_RAW}" \
|
||||
"${INDEXED_VAULT}" "${V3_POOL}" "${V3_SLOT0}" "${V3_LIQUIDITY}" "${V3_TOKEN0_BALANCE}" "${V3_TOKEN1_BALANCE}" \
|
||||
"${V2_PAIR}" "${V2_RESERVES}" "${DEPLOYER:-}" "${WALLET_CWUSDC_RAW}" "${WALLET_USDC_RAW}" <<'PY'
|
||||
from decimal import Decimal
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from datetime import datetime, timezone
|
||||
|
||||
(
|
||||
out_json,
|
||||
out_md,
|
||||
vault,
|
||||
accounting_aware,
|
||||
pool_cw,
|
||||
pool_usdc,
|
||||
lender_usdc,
|
||||
indexed_vault,
|
||||
v3_pool,
|
||||
v3_slot0,
|
||||
v3_liquidity,
|
||||
v3_token0,
|
||||
v3_token1,
|
||||
v2_pair,
|
||||
v2_reserves,
|
||||
deployer,
|
||||
wallet_cw,
|
||||
wallet_usdc,
|
||||
) = sys.argv[1:]
|
||||
|
||||
def units(raw):
|
||||
return str(Decimal(int(raw or 0)) / Decimal(10**6))
|
||||
|
||||
v2_nums = [int(x) for x in re.findall(r"\b\d+\b", v2_reserves or "")]
|
||||
blockers = []
|
||||
if accounting_aware != "1":
|
||||
blockers.append("configured Engine X vault is not accounting-aware")
|
||||
if v3_pool.lower() == "0x0000000000000000000000000000000000000000":
|
||||
blockers.append("UniV3 cWUSDC/USDC public pool is not deployed")
|
||||
if int(v3_liquidity or 0) == 0:
|
||||
blockers.append("UniV3 public pool has zero active liquidity")
|
||||
if not indexed_vault:
|
||||
blockers.append("Engine X indexed-liquidity proof vault is not configured")
|
||||
if not deployer:
|
||||
blockers.append("deployer address unavailable")
|
||||
|
||||
payload = {
|
||||
"schema": "engine-x-public-indexed-readiness/v1",
|
||||
"generatedAt": datetime.now(timezone.utc).isoformat(),
|
||||
"summary": {
|
||||
"readyForPublicIndexedProof": not blockers,
|
||||
"blockers": blockers,
|
||||
},
|
||||
"engineXV2Vault": {
|
||||
"address": vault,
|
||||
"accountingAware": accounting_aware == "1",
|
||||
"poolCwusdcRaw": pool_cw,
|
||||
"poolCwusdc": units(pool_cw),
|
||||
"poolUsdcRaw": pool_usdc,
|
||||
"poolUsdc": units(pool_usdc),
|
||||
"lenderUsdcRaw": lender_usdc,
|
||||
"lenderUsdc": units(lender_usdc),
|
||||
},
|
||||
"indexedProofVault": {"address": indexed_vault or None},
|
||||
"uniV3": {
|
||||
"pool": v3_pool,
|
||||
"slot0": v3_slot0 or None,
|
||||
"liquidity": v3_liquidity,
|
||||
"token0BalanceRaw": v3_token0,
|
||||
"token1BalanceRaw": v3_token1,
|
||||
"token0Balance": units(v3_token0),
|
||||
"token1Balance": units(v3_token1),
|
||||
},
|
||||
"uniV2": {
|
||||
"pair": v2_pair,
|
||||
"rawReserves": v2_nums[:2],
|
||||
},
|
||||
"deployer": {
|
||||
"address": deployer or None,
|
||||
"cwusdcRaw": wallet_cw,
|
||||
"cwusdc": units(wallet_cw),
|
||||
"usdcRaw": wallet_usdc,
|
||||
"usdc": units(wallet_usdc),
|
||||
},
|
||||
}
|
||||
|
||||
Path(out_json).write_text(json.dumps(payload, indent=2) + "\n")
|
||||
lines = [
|
||||
"# Engine X Public Indexed Readiness",
|
||||
"",
|
||||
f"- Generated: `{payload['generatedAt']}`",
|
||||
f"- Ready: `{payload['summary']['readyForPublicIndexedProof']}`",
|
||||
f"- Engine X v2 vault: `{vault}`",
|
||||
f"- Accounting-aware: `{payload['engineXV2Vault']['accountingAware']}`",
|
||||
f"- UniV3 pool: `{v3_pool}`",
|
||||
f"- UniV3 liquidity: `{v3_liquidity}`",
|
||||
f"- Indexed proof vault: `{indexed_vault or 'not configured'}`",
|
||||
f"- Deployer USDC: `{payload['deployer']['usdc']}`",
|
||||
f"- Deployer cWUSDC: `{payload['deployer']['cwusdc']}`",
|
||||
"",
|
||||
"## Blockers",
|
||||
]
|
||||
if blockers:
|
||||
lines.extend(f"- {b}" for b in blockers)
|
||||
else:
|
||||
lines.append("- none")
|
||||
Path(out_md).write_text("\n".join(lines) + "\n")
|
||||
print(out_json)
|
||||
print(out_md)
|
||||
PY
|
||||
@@ -131,6 +131,23 @@ def funding_status(required_raw: int, available_raw: int, decimals: int = 6) ->
|
||||
}
|
||||
|
||||
|
||||
def public_reseed_status(
|
||||
base_shortfall_raw: int,
|
||||
quote_shortfall_raw: int,
|
||||
base_funding: dict,
|
||||
quote_funding: dict,
|
||||
) -> str:
|
||||
if base_shortfall_raw == 0 and quote_shortfall_raw == 0:
|
||||
return "ready"
|
||||
if quote_shortfall_raw > 0 and not quote_funding["covered"]:
|
||||
return "needs_usdc"
|
||||
if base_shortfall_raw > 0 and not base_funding["covered"]:
|
||||
return "needs_cwusdc"
|
||||
if quote_shortfall_raw > 0:
|
||||
return "needs_quote_side_repair"
|
||||
return "needs_base_side_reseed"
|
||||
|
||||
|
||||
def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_override: str) -> dict:
|
||||
rpc_url = resolve_env_value("ETHEREUM_MAINNET_RPC", env_values)
|
||||
if not rpc_url:
|
||||
@@ -217,6 +234,11 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
|
||||
if any("defended quote query failed" in warning for warning in warnings):
|
||||
blockers.append("defended pool quote preview reverted; set MIN_BASE_OUT_RAW manually before any quote-in trade")
|
||||
|
||||
public_deviation_bps = Decimal(str(summary["publicPairDeviationBps"]))
|
||||
public_price_distorted = public_deviation_bps >= Decimal(str(policy["thresholds"]["warnDeviationBps"]))
|
||||
if public_price_distorted:
|
||||
warnings.append("public pair is materially asymmetric; plain addLiquidity follows the current reserve ratio and will not repair price")
|
||||
|
||||
operator_commands = {
|
||||
"rerunPreflight": "bash scripts/verify/snapshot-mainnet-cwusdc-usdc-preflight.sh",
|
||||
"rerunPlan": "bash scripts/verify/plan-mainnet-cwusdc-usdc-repeg.sh",
|
||||
@@ -272,7 +294,42 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
|
||||
]
|
||||
)
|
||||
|
||||
recommended_actions = [
|
||||
if (
|
||||
public_base_shortfall_raw > 0
|
||||
or public_quote_shortfall_raw > 0
|
||||
or public_price_distorted
|
||||
):
|
||||
operator_commands["publicPairRepairGuidance"] = command_block(
|
||||
[
|
||||
"# Public cWUSDC/USDC is one-sided or price-distorted.",
|
||||
"# Do not use addLiquidity by itself as a price repair when only one reserve side is short.",
|
||||
"# Use official Mainnet USDC for a quote-side repair swap first, then add balanced",
|
||||
"# liquidity only after the reserve-implied price is back inside policy gates.",
|
||||
"bash scripts/verify/snapshot-mainnet-cwusdc-usdc-preflight.sh",
|
||||
"bash scripts/verify/plan-mainnet-cwusdc-usdc-repeg.sh",
|
||||
]
|
||||
)
|
||||
|
||||
public_action_status = public_reseed_status(
|
||||
public_base_shortfall_raw,
|
||||
public_quote_shortfall_raw,
|
||||
public_base_funding,
|
||||
public_quote_funding,
|
||||
)
|
||||
needs_external_funding = (
|
||||
not defended_quote_funding["covered"]
|
||||
or not public_base_funding["covered"]
|
||||
or not public_quote_funding["covered"]
|
||||
)
|
||||
recommended_next_action = "execute_verified_repair"
|
||||
if public_quote_shortfall_raw > 0 and not public_quote_funding["covered"]:
|
||||
recommended_next_action = "acquire_official_mainnet_usdc"
|
||||
elif public_quote_shortfall_raw > 0 or public_price_distorted:
|
||||
recommended_next_action = "run_quote_side_public_pair_repair_before_balanced_liquidity"
|
||||
elif add_quote_raw > 0 and not defended_quote_funding["covered"]:
|
||||
recommended_next_action = "acquire_official_mainnet_usdc_for_defended_parity"
|
||||
|
||||
recommended_actions = [
|
||||
{
|
||||
"step": "fund_manager_for_one_max_cycle",
|
||||
"quoteAmountRaw": str(max_automated_raw),
|
||||
@@ -292,11 +349,11 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
|
||||
"baseAmountUnits": str(normalize_units(public_base_shortfall_raw)),
|
||||
"quoteAmountRaw": str(public_quote_shortfall_raw),
|
||||
"quoteAmountUnits": str(normalize_units(public_quote_shortfall_raw)),
|
||||
"status": (
|
||||
"ready"
|
||||
if public_base_shortfall_raw == 0
|
||||
or (public_base_funding["covered"] and public_quote_funding["covered"])
|
||||
else "needs_inventory"
|
||||
"status": public_action_status,
|
||||
"guidance": (
|
||||
"Use quote-side repair before balanced liquidity; plain addLiquidity cannot repair an asymmetric public pair."
|
||||
if public_quote_shortfall_raw > 0 or public_price_distorted
|
||||
else "Use addLiquidity only after price and reserve gates pass."
|
||||
),
|
||||
},
|
||||
]
|
||||
@@ -304,6 +361,23 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
|
||||
return {
|
||||
"generatedAt": datetime.now(timezone.utc).isoformat(),
|
||||
"mode": "read_only_repeg_plan",
|
||||
"summary": {
|
||||
"publicPairBaseReserveUnits": str(public_base_units),
|
||||
"publicPairQuoteReserveUnits": str(public_quote_units),
|
||||
"publicPairDeviationBps": str(summary["publicPairDeviationBps"]),
|
||||
"publicPolicyFloorBaseShortfallUnits": str(normalize_units(public_base_shortfall_raw)),
|
||||
"publicPolicyFloorQuoteShortfallUnits": str(normalize_units(public_quote_shortfall_raw)),
|
||||
"publicPairRepairRequiresQuoteSideAction": public_quote_shortfall_raw > 0 or public_price_distorted,
|
||||
"publicIndexedLpComplianceStatus": (
|
||||
"blocked_missing_quote_side_public_lp_evidence"
|
||||
if public_quote_shortfall_raw > 0 or public_price_distorted
|
||||
else "ready_for_evidence_review"
|
||||
),
|
||||
"defendedAddQuoteUnits": str(normalize_units(add_quote_raw)),
|
||||
"managerFundingShortfallUnits": manager_funding["shortfallUnits"],
|
||||
"needsExternalFunding": needs_external_funding,
|
||||
"recommendedNextAction": recommended_next_action,
|
||||
},
|
||||
"snapshotPath": str(LATEST_SNAPSHOT),
|
||||
"policyPath": str(POLICY_PATH),
|
||||
"inferenceNotes": [
|
||||
@@ -370,11 +444,7 @@ def build_plan(snapshot: dict, policy: dict, env_values: dict[str, str], holder_
|
||||
"blockers": holder_blockers + blockers,
|
||||
"status": {
|
||||
"canFullyReachSimple1To1WithCurrentHolder": len(holder_blockers + blockers) == 0,
|
||||
"needsExternalFunding": (
|
||||
not defended_quote_funding["covered"]
|
||||
or not public_base_funding["covered"]
|
||||
or not public_quote_funding["covered"]
|
||||
),
|
||||
"needsExternalFunding": needs_external_funding,
|
||||
"canFundManagerFromCurrentHolder": holder_usdc_raw >= max_automated_raw if holder_state else None,
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user