chore: sync submodule state (parent ref update)

Made-with: Cursor
This commit is contained in:
defiQUG
2026-03-02 12:14:09 -08:00
parent 50ab378da9
commit 5efe36b1e0
1100 changed files with 155024 additions and 8674 deletions

View File

@@ -63,10 +63,34 @@ Get a quote for bridging tokens to a destination chain.
"minReceived": "999000000000000000",
"estimatedTime": 300,
"slippage": "50",
"riskLevel": 0
"riskLevel": 0,
"sourceSwapQuote": "998000000000000000",
"destinationSwapQuote": "997000000000000000"
}
```
When EnhancedSwapRouter is configured, the response may include `sourceSwapQuote` and `destinationSwapQuote` (best Dodoex-inclusive swap quote on source and destination chain).
### 1b. Swap + Bridge + Swap Quote (full path)
Get a combined quote for swapping on source chain, bridging, then swapping on destination chain.
**Endpoint:** `POST /api/bridge/quote`
**Request Body (extended for swap+bridge+swap):**
```json
{
"sourceToken": "0x...",
"destinationToken": "0x...",
"sourceChainId": 138,
"destinationChainId": 137,
"amount": "1000000000000000000",
"destinationAddress": "0x..."
}
```
**Response:** Same as Get Bridge Quote; `minReceived` reflects the full path when source/destination swap routers are configured. Use `sourceSwapQuote` and `destinationSwapQuote` for per-leg amounts. Initiate flow: (1) source tx: swap + bridge via SwapBridgeSwapCoordinator.swapAndBridge, (2) destination tx: claim + swap via BridgeSwapCoordinator.bridgeAndSwap or coordinator contract.
### 2. Initiate XRPL Bridge
Initiate a bridge transfer to XRPL.

View File

@@ -0,0 +1,98 @@
# Pathway: Chain 138 Only → Canonical Tokens on Other Networks (User Does Not Prefund; Operator Prefunds Destination)
**Prefunding** = Mainnet or an L2 being funded — i.e. someone holds or sends ETH/tokens there so that transfers can complete. If Mainnet or L2 must be funded, that is prefunding (whether the user or the operator does it).
**Question:** Is there a route where you **only use ChainID 138 tokens** and **receive canonical tokens on other networks**, without **you** having to fund Mainnet or L2?
**Answer: Yes — but the destination is still prefunded.** In both pathways below, **you** (the end-user) never fund Mainnet or L2. The **operator** does: they prefund the destination (relayer + LiquidityPool, or Relay Bridge) so you can receive there. So **prefunding is required**; it is done by the operator, not by you. If you deployed the contracts and fund that destination side, you are the operator doing the prefunding.
**Who is the operator?** The party that runs and funds the destination-side infrastructure: for **Trustless**, the relayer and the liquidity providers who fund **LiquidityPoolETH** on Mainnet/L2; for **Relay**, the party that runs the relay service and prefunds the **Relay Bridge** with WETH9 on Mainnet. If you deployed these contracts and you fund the relayer/LP or the Relay Bridge, **you are the operator** (and you are doing the prefunding).
---
## 1. Trustless Bridge (138 → Ethereum Mainnet or L2)
**User experience: Chain 138 only; user does not prefund destination (operator does).**
| Step | Where | Who pays |
|------|--------|----------|
| 1. Deposit | Chain 138 | User: native ETH or WETH into **Lockbox138** |
| 2. Claim | Ethereum (or L2) | **Relayer** (operator): gas + bond on destination |
| 3. Payout | Ethereum (or L2) | **LiquidityPoolETH**: WETH/ETH on destination (operator-funded) |
| 4. Optional swap | Ethereum (or L2) | User can swap to canonical USDC/USDT via DApp “Bridge & Swap” |
- **User** never needs ETH or tokens on mainnet/L2; they only sign on Chain 138.
- **Operator** must fund: relayer (ETH for gas + bonds on destination), LiquidityPool (WETH/ETH on destination).
- **Canonical tokens:** User receives WETH on destination; optionally canonical USDC/USDT via in-app swap.
**References:**
[Trustless Integration](trustless/INTEGRATION.md), [Bridge User Guide](../user/BRIDGE_USER_GUIDE.md), [Trustless Architecture](trustless/ARCHITECTURE.md).
---
## 2. Custom CCIP Relay (138 → Ethereum Mainnet)
**User experience: Chain 138 only; user does not prefund mainnet (operator does).**
| Step | Where | Who pays |
|------|--------|----------|
| 1. Send | Chain 138 | User: WETH9 via bridge + fee on 138 |
| 2. Relay | Off-chain | **Relay service** (operator): gas on mainnet |
| 3. Delivery | Mainnet | **Relay Bridge** must hold WETH9 on mainnet (operator-funded) |
- **User** only interacts on Chain 138; no mainnet balance required.
- **Operator** must prefund the **Relay Bridge** with WETH9 on mainnet so it can complete transfers.
- **Canonical tokens:** User receives canonical WETH9 on mainnet (`0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2`).
**References:**
[Relay Architecture](../relay/ARCHITECTURE.md) — “Bridge Funding: The relay bridge MUST be funded with WETH9 tokens.”
---
## 3. Official CCIP (138 → other chains)
**Not a pathway today.**
- CCIP returns **“chain not supported”** when using Chain 138 as source (or as a hop). No repo change can fix this until Chainlink supports 138.
- When/if supported: user would pay fees **on Chain 138** (LINK or native); destination bridges would still need to be configured and funded by the operator.
---
## Summary
| Pathway | Prefunding of Mainnet/L2? | Who prefunds? | Canonical tokens on destination? |
|--------|---------------------------|---------------|----------------------------------|
| **Trustless** (Lockbox138 → Mainnet/L2) | **Yes** | Operator (LP + relayer on destination) | Yes (WETH; optional swap to USDC/USDT) |
| **Relay** (138 → Mainnet) | **Yes** | Operator (Relay Bridge on mainnet) | Yes (WETH9) |
| **CCIP** (138 → other) | N/A | N/A | Not supported for 138 today |
**Bottom line:** The destination (Mainnet/L2) **is** prefunded — by the operator. You (as end-user) use only Chain 138 and never fund the destination yourself; the operators prefunding is what allows you to receive canonical tokens there. If you deployed and fund the contracts, you are the operator and you are doing that prefunding.
---
## Estimated costs (pathway)
Rough cost breakdown for the two pathways. Gas is variable; assume ~30 gwei on mainnet and chain-specific gas on 138 for illustration.
### User (Chain 138 only)
| Item | Trustless (138 → Mainnet/L2) | Relay (138 → Mainnet) |
|------|------------------------------|-------------------------|
| **On Chain 138** | Deposit: Lockbox138 gas (~72k) | Send WETH9 via bridge + fee (bridge-dependent) |
| **LP / bridge fee** | 0.05% of bridge amount (deducted from received amount) | Per-bridge fee on 138 (if any) |
| **On destination** | None | None |
### Operator (destination side)
| Item | Trustless (138 → Mainnet/L2) | Relay (138 → Mainnet) |
|------|------------------------------|-------------------------|
| **Relayer / service** | Gas on destination: submitClaim ~380k, finalize ~50100k, release ~100150k; bond 110% of deposit (min 1 ETH), returned after finalization | Relay tx gas on mainnet (e.g. up to ~1M gas per message) |
| **Liquidity / bridge** | LiquidityPool: WETH/ETH to cover payouts; min liquidity ratio 110% of pending claims | Relay Bridge: WETH9 balance to cover all transferred amounts |
| **One-time / setup** | Deployment ~510 ETH (gas); initial LP funding | Relay Bridge prefund with expected WETH9 volume |
### Example (Trustless, 10 ETH bridge at 30 gwei mainnet)
| Party | Cost |
|-------|------|
| **User (138 only)** | Chain 138 gas (~72k) + 0.05% × 10 ETH = 0.005 ETH deducted from receive → receives 9.995 ETH (equiv.) on destination |
| **Operator** | Relayer: bond 11 ETH (110% of 10 ETH), returned after finalization; gas ~0.020.05 ETH per claim+finalize+release; LP must hold ≥ 11 ETH (110% of 10) for this claim |

View File

@@ -0,0 +1,54 @@
# Dodoex PMM Full Swappable — Next Steps
## 1. Run create-all-dodo-pools (token coverage)
From repo root (`smom-dbis-138`):
```bash
# Required env (see .env.example):
# RPC_URL, PRIVATE_KEY, QUOTE_TOKEN_ADDRESS, DODO_PMM_INTEGRATION_ADDRESS
# Optional: ENHANCED_SWAP_ROUTER_ADDRESS, UNIVERSAL_ASSET_REGISTRY_ADDRESS,
# TOKEN_AGGREGATION_API_URL, CHAIN_ID (default 138)
# Dry run (no on-chain calls)
DRY_RUN=true CHAIN_ID=138 ./scripts/create-all-dodo-pools-from-token-api.sh
# Live run for chain 138
CHAIN_ID=138 ./scripts/create-all-dodo-pools-from-token-api.sh
# Then for chain 651940 (set RPC_URL and token addresses for that chain)
CHAIN_ID=651940 ./scripts/create-all-dodo-pools-from-token-api.sh
```
Ensure Token Aggregation API is running and has tokens indexed for the chain (e.g. `GET /tokens?chainId=138`).
## 2. Deploy SwapBridgeSwapCoordinator
```bash
# Set ENHANCED_SWAP_ROUTER and UNIVERSAL_CCIP_BRIDGE (or BRIDGE_ORCHESTRATOR)
forge script script/bridge/trustless/DeploySwapBridgeSwapCoordinator.s.sol:DeploySwapBridgeSwapCoordinator \
--rpc-url $RPC_URL --broadcast --legacy
```
Export `SWAP_BRIDGE_SWAP_COORDINATOR` and use it for the swap-then-bridge flow.
## 3. Bridge quote API
Mount the bridge quote routes in your API (e.g. Express):
```ts
import bridgeQuoteRoutes from './orchestration/bridge/bridge-quote-routes';
app.use('/api/bridge', bridgeQuoteRoutes);
```
Set `RPC_URL`, `BRIDGE_REGISTRY_ADDRESS` (and registry ABI); optional: `ENHANCED_SWAP_ROUTER_ADDRESS`, `DESTINATION_RPC_URL`, `DESTINATION_SWAP_ROUTER_ADDRESS`. Then `POST /api/bridge/quote` accepts `token`, `amount`, `destinationChainId`, `destinationAddress` or the swap+bridge+swap shape: `sourceToken`, `destinationToken`, `sourceChainId`, `destinationChainId`, `amount`.
## 4. CCIP and bridge config
- Set CCIP router and chain selectors for 138, 651940, and all target chains (see `docs/deployment/BRIDGE_CONFIGURATION.md`).
- Fund bridge contracts with LINK.
- **SwapBridgeSwapCoordinator**: The bridge accepts any caller; when the coordinator calls `bridge()`, it is `msg.sender` and holds the tokens after the swap, so no extra allowlist is needed. Full details: [CCIP and SwapBridgeSwapCoordinator](trustless/CCIP_AND_SWAP_BRIDGE_COORDINATOR.md).
## 5. Frontend
Set `VITE_BRIDGE_QUOTE_URL` to the base URL of the API that serves `POST /api/bridge/quote`. The Custom Bridge tab documents the request/response; use the "Get full path quote" section to call the API and show `minReceived`, `sourceSwapQuote`, `destinationSwapQuote`.

View File

@@ -0,0 +1,45 @@
# Etherlink Relay Runbook
Runbook for bridging to **Etherlink** (chain 42793) when CCIP does not support Etherlink (custom relay path) or as reference when CCIP is added.
## Branch: CCIP vs Custom Relay
- **If CCIP supports Etherlink**: Use official CCIP lane. Deploy receiver bridges on Etherlink per [DeployWETHBridges.s.sol](script/deploy/bridge/DeployWETHBridges.s.sol) and [execute-bridge-config.sh](scripts/deployment/execute-bridge-config.sh). Configure addDestination on source (138, 651940 if ever CCIP) with Etherlink chain selector and receiver addresses. Fund LINK. No custom relay needed.
- **If CCIP does not support Etherlink**: Use **custom relay** (this runbook). Same pattern as 138→Mainnet in [relay ARCHITECTURE](relay/ARCHITECTURE.md).
## Custom Relay Path (when CCIP not available)
### Components
1. **Source chain(s)** (e.g. ChainID 138 or ALL Mainnet)
- Bridge contract (UniversalCCIPBridge or WETH bridge) that locks tokens and emits events (e.g. MessageSent or equivalent).
2. **Relay service (off-chain)**
- Event monitor: listen for bridge/router events for destination Etherlink (chainId 42793).
- Message queue: queue detected messages; retry; idempotency.
- Token mapping: source token address → Etherlink token address.
- Submit on Etherlink: call relay-compatible receiver contract to mint/unlock and transfer to recipient.
3. **Etherlink (42793)**
- **Relay-compatible receiver**: Contract that accepts relay-submitted payloads (sender, token, amount, recipient); mints or unlocks and transfers. Must be authorized (e.g. only relayer key can call).
### Receiver interface (Etherlink)
- Function: e.g. `relayMintOrUnlock(bytes32 messageId, address token, address recipient, uint256 amount)` or equivalent.
- Access control: only relayer (or authorized bridge) can call.
- Replay: use `messageId` (or source chain tx hash) for idempotency.
### Env
- `ETHERLINK_RPC_URL` (e.g. `https://node.mainnet.etherlink.com`).
- `ETHERLINK_RELAY_BRIDGE`: receiver contract on Etherlink.
- `ETHERLINK_RELAY_PRIVATE_KEY`: key that holds authority on receiver (or relayer role).
### Deployment on Etherlink (custom relay)
1. Deploy receiver contract (relay-compatible: accept relayMintOrUnlock-style calls).
2. Deploy or map wrapped token contracts if needed.
3. Configure relay service: source RPC, Etherlink RPC, receiver address, token mapping, private key.
## References
- [relay ARCHITECTURE](relay/ARCHITECTURE.md) (138→Mainnet pattern).
- [TEZOS_CCIP_DON_PREREQUISITES](../../docs/07-ccip/TEZOS_CCIP_DON_PREREQUISITES.md): verify CCIP first; if not listed, use this runbook.

View File

@@ -71,6 +71,8 @@ npm run dev
- [API Documentation](./API_DOCUMENTATION.md) - Complete API reference
- [Deployment Guide](./DEPLOYMENT_GUIDE.md) - Step-by-step deployment instructions
- [Runbook](./RUNBOOK.md) - Operations and troubleshooting guide
- [Dodoex PMM Next Steps](./DODO_PMM_NEXT_STEPS.md) - Token coverage and swap+bridge+swap setup
- [CCIP and SwapBridgeSwapCoordinator](./trustless/CCIP_AND_SWAP_BRIDGE_COORDINATOR.md) - CCIP config and atomic swap-then-bridge coordinator
## Architecture

View File

@@ -0,0 +1,22 @@
# TezosAdapter Production Checklist
Production readiness for Tezos L1 bridging via TezosAdapter and BridgeRegistry/ChainRegistry.
## Contracts
- **TezosAdapter**: Deployed via [DeployAllAdapters.s.sol](script/deploy/chains/DeployAllAdapters.s.sol). No new Tezos L1 EVM contracts required.
- **BridgeRegistry**: Tezos-Mainnet registered with chainId **1** (non-EVM) in [InitializeRegistry.s.sol](scripts/bridge/interop/InitializeRegistry.s.sol). Ensure registry is initialized (run script or call registerDestination(1, "Tezos-Mainnet", ...)).
- **ChainRegistry**: Tezos-Mainnet registered via DeployAllAdapters as `registerNonEVMChain("Tezos-Mainnet", ChainType.Other, tezosAdapter, "https://tzkt.io", ...)`.
## Token config
- For tokens that may bridge to Tezos L1, include **1** in allowedDestinations when registering with BridgeRegistry or integration contracts (VaultBridgeIntegration, eMoneyBridgeIntegration, WTokenBridgeIntegration). BRG scripts: see [register-vault-deposit-tokens.sh](scripts/bridge/register-vault-deposit-tokens.sh), [register-iso-deposit-tokens.sh](scripts/bridge/register-iso-deposit-tokens.sh) (comments reference 42793 and 1).
## Relay
- Operate relay per [TEZOS_L1_RELAY_RUNBOOK.md](TEZOS_L1_RELAY_RUNBOOK.md): event monitor, Tezos-side mint/transfer, confirmTransaction with ORACLE_ROLE. Oracle key handling and Tezos-side spec documented there.
## References
- [TEZOS_BRIDGE_DEPLOYMENT](../../docs/03-deployment/TEZOS_BRIDGE_DEPLOYMENT.md)
- [TEZOS_L1_RELAY_RUNBOOK](TEZOS_L1_RELAY_RUNBOOK.md)

View File

@@ -0,0 +1,32 @@
# Tezos Bridge E2E Runbook
End-to-end flow for Tezos L1 bridging: deploy TezosAdapter and relay, run E2E on testnet (Ghostnet), then mainnet with rate limits.
## Prerequisites
- TezosAdapter deployed via [DeployAllAdapters.s.sol](script/deploy/chains/DeployAllAdapters.s.sol).
- BridgeRegistry destination chainId 1 (Tezos-Mainnet) registered via [InitializeRegistry.s.sol](scripts/bridge/interop/InitializeRegistry.s.sol).
- ChainRegistry: Tezos-Mainnet registered (ChainType.Other).
- Relay service: event monitor + Tezos-side mint/transfer + confirmTransaction (see [TEZOS_L1_RELAY_RUNBOOK](TEZOS_L1_RELAY_RUNBOOK.md)).
## E2E on Ghostnet (Tezos testnet)
1. Deploy a test TezosAdapter on an EVM testnet (e.g. ChainID 138 testnet or local anvil).
2. Run relay against Ghostnet: configure Tezos RPC for Ghostnet; map test token to a Ghostnet FA1.2/FA2 or custody account.
3. User flow: call TezosAdapter.bridge(token, amount, destination, recipient) with a Ghostnet Tezos address (tz1/...).
4. Relay: watch TezosBridgeInitiated, mint/transfer on Ghostnet, call confirmTransaction(requestId, tezosOpHash).
5. Verify: getBridgeStatus(requestId) shows Confirmed; Tezos balance updated.
## Mainnet with rate limits
1. Deploy TezosAdapter and register on production (138 or target chain).
2. Run relay with mainnet Tezos RPC; use production token mapping and custody/mint contracts.
3. Apply rate limits and caps per token/chain (BridgeRegistry token config: minAmount, maxAmount, bridgeFeeBps).
4. Monitor: log all TezosBridgeInitiated and confirmTransaction calls; alert on failures and duplicates.
## Checklist
- [ ] TezosAdapter deployed and registered in ChainRegistry and BridgeRegistry.
- [ ] Relay running with ORACLE_ROLE; key secured.
- [ ] E2E passed on Ghostnet (or equivalent testnet).
- [ ] Rate limits and caps configured; monitoring in place.

View File

@@ -0,0 +1,7 @@
# Tezos / Etherlink Integration Testing
Integration tests for Tezos and Etherlink bridging.
- Unit: forge test --match-path test/bridge/adapters/TezosAdapter.t.sol. BridgeRegistry/ChainRegistry tests with 42793 and chainId 1.
- Integration: Deploy on local/anvil; run lock -> event -> relay (mock confirmTransaction); test BridgeRegistry, ChainRegistry, integration contracts with 42793 and 1.
- Cross-chain sim: Anvil fork + relay or DON simulator; Tezos Ghostnet per TEZOS_E2E_RUNBOOK.md.

View File

@@ -0,0 +1,85 @@
# Tezos L1 Relay Runbook
This runbook describes how an off-chain relay service should integrate with the **TezosAdapter** to complete bridge operations from an EVM chain to Tezos L1 (native Michelson).
## Overview
- **TezosAdapter** (EVM side): Locks tokens on the source chain and emits events when a bridge is initiated.
- **Relay service** (off-chain): Watches these events, performs the Tezos-side mint/transfer, then calls `confirmTransaction(requestId, tezosTxHash)` on the adapter.
## TezosAdapter Event Schema
### TezosBridgeInitiated
Emitted when a user calls `bridge(token, amount, destination, recipient)` on the TezosAdapter.
| Parameter | Type | Description |
|------------|---------|-------------|
| requestId | bytes32 | Unique request identifier (use for confirmTransaction). |
| sender | address | EVM address that initiated the bridge. |
| token | address | Token contract address (address(0) for native ETH). |
| amount | uint256 | Amount locked. |
| destination| string | Tezos address (tz1/tz2/tz3/KT1) to receive on Tezos. |
**Relay responsibilities:**
1. Index or subscribe to `TezosBridgeInitiated` events from the TezosAdapter contract.
2. Decode `requestId`, `sender`, `token`, `amount`, `destination`.
3. Map `token` to the Tezos-side wrapped/representative asset (e.g. FA1.2/FA2 or custody account).
4. On Tezos: mint wrapped tokens to `destination` or release from custody to `destination` (depending on bridge design).
5. After the Tezos transaction is confirmed, call on the EVM TezosAdapter:
- `confirmTransaction(requestId, tezosTxHash)` (requires ORACLE_ROLE).
## TezosAdapter Methods (for relay)
| Method | Role | Description |
|--------|------|-------------|
| `confirmTransaction(bytes32 requestId, string txHash)` | ORACLE_ROLE | Mark the bridge request as confirmed and store the Tezos tx hash. |
| `getBridgeStatus(bytes32 requestId)` | any | Returns BridgeRequest (status, sender, token, amount, destinationData, etc.). |
## Destination Validation
TezosAdapter accepts destinations that pass `validateDestination(destination)`:
- `destination` is the UTF-8 encoding of a Tezos address (tz1, tz2, tz3, or KT1).
- Length must be between 35 and 64 bytes.
## Relay Flow (high level)
```text
User -> TezosAdapter.bridge(...) -> tokens locked, TezosBridgeInitiated emitted
-> Relay watches event
-> Relay performs Tezos-side mint/transfer to destination
-> Relay calls TezosAdapter.confirmTransaction(requestId, tezosTxHash)
```
## Oracle Key Handling
- **ORACLE_ROLE**: The relay (or a dedicated oracle) must hold ORACLE_ROLE on the TezosAdapter to call `confirmTransaction`. Grant via `grantRole(ORACLE_ROLE, relayAddress)`.
- **Key material**: Store relay/oracle private key securely (HSM or secrets manager); never commit to repo.
- **Rotation**: To rotate oracle key: deploy new relay with new key, grant ORACLE_ROLE to new address, revoke from old address, then retire old relay.
- **Backup**: Document backup and recovery for oracle key so confirmTransaction can continue after relay failure.
## Tezos-Side Mint/Transfer Spec
- **Wrapped representation**: Map each EVM `token` to a Tezos asset (FA1.2/FA2 token contract or custody account). Maintain a config map: EVM token address -> Tezos contract/account.
- **Flow**: On Tezos, either (1) call a mint entrypoint on the wrapped-token contract to mint `amount` to `destination`, or (2) transfer from a custody account to `destination`. Use Tezos RPC (e.g. TzKT or node) to submit the operation.
- **Finality**: Only after the Tezos operation is included and finalized (e.g. 1 confirmation on Tezos), call `confirmTransaction(requestId, tezosTxHash)` with the Tezos operation hash.
## Security and Operations
- The relay (or a dedicated oracle) must hold **ORACLE_ROLE** on the TezosAdapter to call `confirmTransaction`.
- Only call `confirmTransaction` after the Tezos transaction is finalized to avoid marking incomplete transfers as confirmed.
- Tezos L1 uses chainId **1** in BridgeRegistry (non-EVM slot); include **1** in token `allowedDestinations` for tokens that may bridge to Tezos L1.
## Run instructions and env (relay service)
- **Service**: `smom-dbis-138/services/tezos-relay` (Node.js).
- **Env**: `TEZOS_ADAPTER_ADDRESS`, `TEZOS_RELAY_ORACLE_KEY` or `PRIVATE_KEY` (EVM key for confirmTransaction), `RPC_URL_138`. For real Tezos mint: `TEZOS_RPC_URL`, `TEZOS_MINTER_ADDRESS`, `TEZOS_ORACLE_SECRET_KEY` (Tezos edsk...). Set `MOCK_TEZOS_RELAY=true` to use mock hash only (no Taquito).
- **Start**: `cd services/tezos-relay && npm install && node index.js` (or `npm start`). Optional: add `@taquito/taquito` and `@taquito/signer` for real mint/transfer.
## References
- **TezosAdapter**: `smom-dbis-138/contracts/bridge/adapters/non-evm/TezosAdapter.sol`
- **IChainAdapter**: `smom-dbis-138/contracts/bridge/interfaces/IChainAdapter.sol`
- **BridgeRegistry** (Tezos-Mainnet destination): chainId 1; see `InitializeRegistry.s.sol`.

View File

@@ -0,0 +1,23 @@
# Token List Extension for Tezos and Etherlink
How to add Etherlink (42793) and Tezos L1 to token list and UniversalAssetRegistry for cross-chain bridging.
## Allowed destinations (BridgeRegistry)
- **Etherlink**: chainId **42793**. Already in default destinations in VaultBridgeIntegration, eMoneyBridgeIntegration, WTokenBridgeIntegration. When registering tokens with BridgeRegistry or integration contracts, include **42793** in allowedDestinations (or use default).
- **Tezos L1**: chainId **1** in BridgeRegistry (non-EVM slot). Include **1** in allowedDestinations for tokens that may bridge to Tezos L1.
## Token list schema (Uniswap-style)
- **Etherlink (42793)**: Add a token list or extend existing list with tokens that have `chainId: 42793`. Same structure as other chains: chainId, address, name, symbol, decimals. File location: follow project [TOKEN_LIST_AUTHORING_GUIDE](docs/11-references/TOKEN_LIST_AUTHORING_GUIDE.md) and [ADDING_NEW_ASSET_TYPE](guides/ADDING_NEW_ASSET_TYPE.md) and token-lists layout; add or reference a list that includes 42793.
- **Tezos L1**: Uniswap token list is EVM-only (chainId + address). For Tezos-origin or wrapped-on-Tezos assets, document in registry/metadata; BridgeRegistry destination 1 does not require a token list entry for Tezos-native assets. For EVM-side wrapped representations of Tezos assets (if any), use the chainId of the EVM chain where the wrapped token lives.
## UniversalAssetRegistry
- Register new tokens (Etherlink/Tezos wrapped or origin) in UniversalAssetRegistry with appropriate AssetType and ComplianceLevel.
- Use governance (submitTokenlistVersion + timelock via TokenlistGovernanceSync) to add tokens; or register directly with REGISTRAR_ROLE if policy allows.
- Ensure BridgeRegistry and integration contracts (VaultBridgeIntegration, eMoneyBridgeIntegration, WTokenBridgeIntegration) allow **42793** and **1** in allowedDestinations. Defaults already include 42793; for Tezos L1 include 1 when registering tokens.
## TokenlistGovernanceSync
- If token list schema is extended (e.g. new chainIds 42793 or metadata for Tezos), extend TokenlistGovernanceSync or submission process to support new chainIds/metadata. Current flow: submitTokenlistVersion(major, minor, patch, ipfsHash, newTokens, metadata). Ensure metadata includes chainId/destination info where needed.

View File

@@ -0,0 +1,19 @@
# Bridge Upgrade and Pause Runbooks
Upgrade paths and pause procedures for bridge contracts (Tezos/Etherlink context).
## Upgrade paths
- **Upgradeable (UUPS)**: UniversalAssetRegistry, BridgeOrchestrator, GovernanceController, TokenlistGovernanceSync. Upgrade via UPGRADER_ROLE after timelock if policy requires. Run: prepare upgrade (new impl), schedule timelock, execute upgrade.
- **Non-upgradeable**: TezosAdapter, EVMAdapter, AlltraCustomBridge. Deploy new version; register new adapter in ChainRegistry (or update adapter address); phase out old (revoke roles, drain if any).
- **CCIP Router**: Per Chainlink; DON upgrades are separate from application contracts.
## Pause procedures
- **BridgeRegistry**: If contract has Pausable, call pause() with appropriate role (e.g. DEFAULT_ADMIN_ROLE). Stops new token/destination registration and optionally bridge operations if enforced in routing.
- **TezosAdapter**: setIsActive(false) with DEFAULT_ADMIN_ROLE. Stops new bridge() calls; in-flight requests can still be confirmed by oracle.
- **UniversalCCIPBridge / WETH bridges**: If pausable, pause to stop new outbound messages; coordinate with DON/relay to avoid stuck messages.
## Security
- Document key holders for UPGRADER_ROLE and pause roles; use multisig where required. Runbooks: key rotation, incident response (pause first, then investigate).

View File

@@ -0,0 +1,120 @@
# CCIP Configuration and SwapBridgeSwapCoordinator
This document covers CCIP setup for the trustless bridge and the **SwapBridgeSwapCoordinator** contract used for atomic swap-then-bridge flows (Dodoex PMM on source chain → CCIP bridge).
## Overview
- **UniversalCCIPBridge**: Main bridge contract; accepts any caller. It pulls tokens from `msg.sender`, sends a CCIP message, and emits `BridgeExecuted` with `msg.sender` as the sender.
- **SwapBridgeSwapCoordinator**: Wraps “swap on source chain” + “bridge” in one transaction. The user approves the coordinator; the coordinator swaps via `EnhancedSwapRouter` (Dodoex), then calls `UniversalCCIPBridge.bridge()`. When the bridge runs, `msg.sender` is the coordinator (which holds the bridgeable tokens after the swap), so no extra allowlist is required for the coordinator.
## CCIP Configuration
### Prerequisites
1. **CCIP Router** deployed and configured on each chain (138, 651940, and any target chains).
2. **Chain selectors** known for every source and destination chain.
3. **UniversalCCIPBridge** (or equivalent) deployed and initialized with the correct CCIP router and asset registry.
### Chain selectors
- Obtain selectors from your CCIP Router (e.g. `getChainSelector()`) or from Chainlinks [CCIP supported networks](https://docs.chain.link/ccip/supported-networks).
- For Chain 138 and custom chains, see `docs/deployment/CHAIN138_SELECTOR_NOTES.md` and your `networks.json` / relay config.
- Common reference (see `docs/deployment/BRIDGE_CONFIGURATION.md` for full table):
- Ethereum Mainnet: `5009297550715157269`
- Polygon: `4051577828743386545`
- Base: `15971525489660198786`
- Arbitrum: `4949039107694359620`
- Optimism: `3734403246176062136`
### Destinations and LINK
1. **Destinations**: For each bridgeable token, configure `destinations[token][destinationChainSelector]` (receiver bridge address and enabled flag) on `UniversalCCIPBridge`. Use the contracts admin/configuration interface (e.g. addDestination / setDestination).
2. **LINK**: Fund each bridge contract with LINK so it can pay CCIP fees. Example:
```bash
cast send $LINK_TOKEN "transfer(address,uint256)" $UNIVERSAL_CCIP_BRIDGE $AMOUNT --rpc-url $RPC_URL --private-key $PRIVATE_KEY
```
Recommended: start with ~10 LINK per bridge; adjust based on traffic.
### References
- Bridge configuration and chain table: `docs/deployment/BRIDGE_CONFIGURATION.md`
- Operations: `docs/operations/integrations/BRIDGE_CONFIGURATION.md`, `docs/operations/integrations/CCIP_ROUTER_SETUP.md`
- Env vars: `docs/bridge/trustless/ENV_VARIABLES_REFERENCE.md`
---
## SwapBridgeSwapCoordinator
### Role
- **Problem**: Users often hold token A but want to bridge token B (e.g. WETH or a stable). Doing “swap then bridge” in two steps is two transactions and worse UX.
- **Solution**: SwapBridgeSwapCoordinator performs in one transaction:
1. Pull `sourceToken` from the user.
2. If `sourceToken != bridgeableToken`, swap to `bridgeableToken` via `EnhancedSwapRouter.swapTokenToToken` (Dodoex).
3. Call `UniversalCCIPBridge.bridge()` with the bridgeable token; the bridge pulls from the coordinator (`msg.sender`).
### Deployment
**Env (required):**
- `PRIVATE_KEY` deployer.
- `ENHANCED_SWAP_ROUTER` EnhancedSwapRouter address on the same chain.
- `UNIVERSAL_CCIP_BRIDGE` or `BRIDGE_ORCHESTRATOR` bridge contract address.
**Deploy:**
```bash
# From repo root (smom-dbis-138)
export RPC_URL=... # Chain 138 or 651940 RPC
export ENHANCED_SWAP_ROUTER=0x...
export UNIVERSAL_CCIP_BRIDGE=0x...
forge script script/bridge/trustless/DeploySwapBridgeSwapCoordinator.s.sol:DeploySwapBridgeSwapCoordinator \
--rpc-url $RPC_URL --broadcast --legacy
```
Then set in env and frontend:
```bash
export SWAP_BRIDGE_SWAP_COORDINATOR=0x...
```
Script path: `script/bridge/trustless/DeploySwapBridgeSwapCoordinator.s.sol`.
### Contract interface (summary)
- **Constructor**: `SwapBridgeSwapCoordinator(swapRouter, bridge)`.
- **Main entry**: `swapAndBridge(sourceToken, amountIn, amountOutMin, bridgeableToken, destinationChainSelector, recipient, assetType, usePMM, useVault)`.
- User must approve the coordinator for `sourceToken` (and for native gas, the call can send `msg.value` to the bridge).
- `amountOutMin` is slippage protection when a swap is performed; ignored if `sourceToken == bridgeableToken`.
- **Events**: `SwapAndBridgeExecuted(sourceToken, bridgeableToken, amountIn, amountBridged, destinationChainSelector, recipient, messageId)`.
### Access control (msg.sender)
- **UniversalCCIPBridge.bridge()** does not restrict callers. It does:
- `IERC20(op.token).safeTransferFrom(msg.sender, address(this), op.amount)`
- Then sends the CCIP message and uses `msg.sender` for nonces and events.
- When the **SwapBridgeSwapCoordinator** calls `bridge()`, `msg.sender` is the coordinator. The coordinator holds the bridgeable tokens after the swap and has approved the bridge, so the transfer and CCIP send succeed. No separate allowlist or role for the coordinator is required on the bridge.
### Integration checklist
- [ ] CCIP router and chain selectors set for 138, 651940, and target chains.
- [ ] Bridge contracts funded with LINK.
- [ ] `UniversalCCIPBridge` destinations set for each token and destination chain.
- [ ] SwapBridgeSwapCoordinator deployed and `SWAP_BRIDGE_SWAP_COORDINATOR` set in env and frontend.
- [ ] Dodoex PMM pools and `EnhancedSwapRouter` configured for the tokens you use (see `docs/bridge/DODO_PMM_NEXT_STEPS.md`).
---
## End-to-end flow
1. **Quote**: Frontend or backend calls `POST /api/bridge/quote` with swap+bridge+swap parameters; response can include `sourceSwapQuote`, `destinationSwapQuote`, and bridge fee/minReceived (see `docs/bridge/API_DOCUMENTATION.md`).
2. **User approval**: User approves `SWAP_BRIDGE_SWAP_COORDINATOR` for `sourceToken` (and optionally sends native token for CCIP fees).
3. **Execute**: User (or relayer) calls `SwapBridgeSwapCoordinator.swapAndBridge(...)` with the same parameters as the quote (or derived from it).
4. **On-chain**: Coordinator swaps then calls `UniversalCCIPBridge.bridge()`; CCIP delivers to the destination receiver contract; recipient receives the bridgeable token (or downstream swap is done separately on destination).
For full path quote and frontend wiring, see:
- `docs/bridge/DODO_PMM_NEXT_STEPS.md`
- `docs/bridge/API_DOCUMENTATION.md` (quote and swap+bridge+swap)
- `docs/bridge/trustless/ENV_VARIABLES_REFERENCE.md` (all env vars, including quote service and coordinator)

View File

@@ -318,6 +318,20 @@ cast call $STABLECOIN_PEG_MANAGER \
4. **Liquidity Pool Empty**: Provide initial liquidity
5. **Reserve Insufficient**: Fund ReserveSystem
### Live-test cast errors (lock / claim / finalize)
- **`-32602: Invalid params`** — Wrong RPC for the tx (e.g. mainnet RPC for a 138 lock), or missing/corrupt env (PRIVATE_KEY, RPC_URL_138, ETHEREUM_MAINNET_RPC). Ensure lock uses `--rpc-url $RPC_URL_138` and claim/finalize use `--rpc-url $ETHEREUM_MAINNET_RPC`. Check `.env` has no typos (e.g. `PRIVATE_KEYIT_ID`).
- **`invalid string length` (e.g. for `1000000000000000`)** — You passed the **amount** (AMOUNT_WEI) where an **address** or **depositId** is expected. **DEPOSIT_ID** must be the **depositId** from the Lockbox `Deposit` event (a large uint256 from the event), **not** the amount. Get it with:
```bash
cast logs <LOCK_TX_HASH> "Deposit(uint256,address,uint256,address,bytes32,address,uint256)" --rpc-url $RPC_URL_138
```
Use the first decoded argument as `DEPOSIT_ID`.
- **`encode length mismatch: expected 1 types, got 0`** — **DEPOSIT_ID** is empty or unset for `claim` or `finalize`. Set it from the lock tx event as above.
**Quick DEPOSIT_ID from lock tx:**
`export DEPOSIT_ID=$(./scripts/deployment/run-e2e-trustless-live-test.sh get-deposit-id <LOCK_TX_HASH>)`
Then run `AMOUNT_WEI=1000000000000000 ./scripts/deployment/run-e2e-trustless-live-test.sh claim`.
### Emergency Procedures
1. **Pause System**: Use pause functions if available
@@ -337,3 +351,15 @@ After deployment:
See `OPERATIONS_GUIDE.md` for operational procedures.
---
## Deploy, Configure, and Live Test (single flow)
**Deploy:** Run trustless phase: `./scripts/deployment/deploy-all-mainnets-with-mapper-oracle-pmm.sh trustless` (from smom-dbis-138). Set LOCKBOX_138, BOND_MANAGER, LIQUIDITY_POOL, INBOX_ETH, CHALLENGE_MANAGER in .env.
**Configure:** (1) Verify Inbox is authorized on LP: `cast call $LIQUIDITY_POOL "authorizedRelease(address)(bool)" $INBOX_ETH --rpc-url $ETHEREUM_MAINNET_RPC`. (2) Initialize if using router: `forge script script/bridge/trustless/InitializeBridgeSystem.s.sol:InitializeBridgeSystem --rpc-url $ETHEREUM_MAINNET_RPC --broadcast --via-ir`. (3) Fund LP: `./scripts/deployment/fund-mainnet-lp.sh --eth 2 --weth 1`.
**Verify:** `./scripts/deployment/verify-trustless-deployments.sh`.
**Live test with actual tokens (138 to mainnet):** (1) Lock: `cast send $LOCKBOX_138 "depositNative(address,bytes32)" RECIPIENT NONCE --value 0.01ether --rpc-url $RPC_URL_138 --private-key $PRIVATE_KEY --legacy`. (2) Get depositId from Deposit event. (3) Submit claim: `cast send $INBOX_ETH "submitClaim(uint256,address,uint256,address,bytes)" DEPOSIT_ID 0x0 AMOUNT_WEI RECIPIENT 0x --value BOND --rpc-url $ETHEREUM_MAINNET_RPC --private-key $PRIVATE_KEY` (BOND = getRequiredBond(amount)). (4) Wait challenge window. (5) Finalize: `cast send $CHALLENGE_MANAGER "finalizeClaim(uint256)" DEPOSIT_ID ...`. (6) Release bond: `cast send $BOND_MANAGER "releaseBond(uint256)" DEPOSIT_ID ...`. See runbook: `scripts/deployment/live-test-trustless-bridge.sh` (prints commands and optional checks).

View File

@@ -0,0 +1 @@
# Deploy Configure Live Test

View File

@@ -0,0 +1,153 @@
# Optional Upgrade: EnhancedSwapRouter
This runbook describes what you need to do to deploy and use the **EnhancedSwapRouter** (multi-protocol swap: Uniswap V3, Dodoex, Curve, Balancer, 1inch) on Ethereum Mainnet.
---
## 1. Prerequisites
- **Chain**: Ethereum Mainnet (Chain ID 1) only (script enforces this).
- **.env** (in `smom-dbis-138/` or project root) with:
- `PRIVATE_KEY` — deployer key (has mainnet ETH for gas).
- `ETHEREUM_MAINNET_RPC` — mainnet RPC (Infura/Alchemy recommended).
- `ETHERSCAN_API_KEY` — for contract verification (optional but recommended).
---
## 2. Deploy EnhancedSwapRouter
From repo root `smom-dbis-138/`:
```bash
cd /home/intlc/projects/proxmox/smom-dbis-138
set -a && [ -f .env ] && source .env && set +a
forge script script/bridge/trustless/DeployEnhancedSwapRouter.s.sol:DeployEnhancedSwapRouter \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
--broadcast \
--via-ir \
--verify \
--etherscan-api-key "$ETHERSCAN_API_KEY"
```
Or use the phase-3 script:
```bash
./scripts/deployment/phase3-deploy-router.sh
```
**Save the deployed address** from the script output and add to `.env`:
```bash
ENHANCED_SWAP_ROUTER=0x...
```
---
## 3. Configure Balancer pool IDs (optional)
EnhancedSwapRouter uses Balancer for medium/large swaps. If you use those tiers, set pool IDs for the pairs you need (e.g. WETHUSDC, WETHUSDT):
```bash
# Example: WETHUSDT Balancer pool ID (replace <poolId> with actual bytes32)
cast send $ENHANCED_SWAP_ROUTER \
"setBalancerPoolId(address,address,bytes32)" \
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
0xdAC17F958D2ee523a2206206994597C13D831ec7 \
<poolId> \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
--private-key "$PRIVATE_KEY"
```
Find pool IDs from [Balancer](https://app.balancer.fi/) or their subgraph for mainnet.
---
## 4. Grant COORDINATOR_ROLE (for future coordinator use)
If you later deploy a coordinator that uses EnhancedSwapRouter (see §6), that coordinator must have `COORDINATOR_ROLE` on EnhancedSwapRouter. You can grant it to the **existing** BridgeSwapCoordinator so its ready if you switch to a coordinator that calls EnhancedSwapRouter:
```bash
# Role hash (COORDINATOR_ROLE)
cast keccak "COORDINATOR_ROLE"
# Grant to BridgeSwapCoordinator (replace with your BRIDGE_SWAP_COORDINATOR address)
cast send $ENHANCED_SWAP_ROUTER \
"grantRole(bytes32,address)" \
$(cast keccak "COORDINATOR_ROLE") \
"$BRIDGE_SWAP_COORDINATOR" \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
--private-key "$PRIVATE_KEY"
```
---
## 5. Customize routing (optional)
Default routing is:
- **Small** (&lt; $10k): Uniswap V3, Dodoex
- **Medium** ($10k$100k): Dodoex, Balancer, Uniswap V3
- **Large** (&gt; $100k): Dodoex, Curve, Balancer
To change providers per size category (e.g. `setRoutingConfig`), use the contracts `setRoutingConfig(sizeCategory, providers[])` with the provider enum values (see `EnhancedSwapRouter.SwapProvider`).
---
## 6. Important: BridgeSwapCoordinator and EnhancedSwapRouter
The **current** **BridgeSwapCoordinator** (trustless bridge payout) is wired to the **basic SwapRouter** in code:
- It calls `swapRouter.swapToStablecoin(..., bytes calldata routeData)` and expects a single `uint256` return.
- **EnhancedSwapRouter** exposes `swapToStablecoin(..., SwapProvider preferredProvider)` and returns `(uint256, SwapProvider)`.
So the existing coordinator **cannot** call EnhancedSwapRouter without a contract change. Today:
- **bridgeAndSwap** (Lockbox → claim → release → swap to USDT/USDC) still uses the **basic SwapRouter** only.
- Deploying EnhancedSwapRouter gives you:
- Multi-protocol routing for **other** callers (e.g. quote services, liquidity engine, or direct `EnhancedSwapRouter.swapToStablecoin` calls).
- A path ready for a **future** coordinator (or upgraded coordinator) that uses EnhancedSwapRouter once one is implemented and deployed.
To actually use EnhancedSwapRouter for the trustless payout flow you would need to:
- Implement and deploy a new coordinator (or upgrade) that takes an EnhancedSwapRouter-compatible interface and calls `swapToStablecoin(..., preferredProvider)` with the right parameters and return handling, and
- Point the LPs authorized releaser (or users) at that new coordinator instead of the current BridgeSwapCoordinator.
---
## 7. Summary checklist
| Step | Action |
|------|--------|
| 1 | Set `PRIVATE_KEY`, `ETHEREUM_MAINNET_RPC`, `ETHERSCAN_API_KEY` in `.env`. |
| 2 | Run `DeployEnhancedSwapRouter.s.sol` (or `phase3-deploy-router.sh`) on mainnet. |
| 3 | Add `ENHANCED_SWAP_ROUTER=<address>` to `.env`. |
| 4 | (Optional) Configure Balancer pool IDs for WETHstable pairs. |
| 5 | (Optional) Grant `COORDINATOR_ROLE` on EnhancedSwapRouter to BridgeSwapCoordinator for future use. |
| 6 | (Optional) Adjust routing via `setRoutingConfig` if needed. |
**References:** `DEPLOYMENT_GUIDE.md`, `DEPLOYMENT_SUMMARY.md`, `script/bridge/trustless/DeployEnhancedSwapRouter.s.sol`, `scripts/deployment/phase3-deploy-router.sh`.
---
## 8. Completed deployment (2026-02-20)
- **EnhancedSwapRouter** deployed at `0xc99f13275a3a85f556570767f1Fc3e58788f777d` (Ethereum Mainnet).
- Default routing configured (small: Uniswap V3 + Dodoex; medium: Dodoex + Balancer + Uniswap V3; large: Dodoex + Curve + Balancer).
- **COORDINATOR_ROLE** granted to BridgeSwapCoordinator (`0xF51581eee46f5A7Ef2A035C5B3Ac4a89bF6FbaAa`).
- **Balancer pool IDs**: optional; set via `setBalancerPoolId(tokenA, tokenB, poolId)` when you have pool IDs from [Balancer](https://app.balancer.fi/) or the Balancer subgraph.
---
## 9. DualRouterBridgeSwapCoordinator (bridgeAndSwap with basic or enhanced router)
A **DualRouterBridgeSwapCoordinator** contract is deployed so that one coordinator can perform `bridgeAndSwap` using either the basic SwapRouter or the EnhancedSwapRouter.
- **Contract**: `contracts/bridge/trustless/DualRouterBridgeSwapCoordinator.sol`
- **Deployed at (Ethereum Mainnet)**: `0x5BB7e48DA5f571344E08BDB4f0d3CE2198963EcD`
- **Signature**: `bridgeAndSwap(depositId, recipient, outputAsset, stablecoinToken, amountOutMin, routeData, useEnhancedRouter)`
- `useEnhancedRouter == false`: uses basic SwapRouter (same as existing BridgeSwapCoordinator).
- `useEnhancedRouter == true`: uses EnhancedSwapRouter (multi-protocol routing).
- **Deploy script**: `script/bridge/trustless/DeployDualRouterBridgeSwapCoordinator.s.sol` (env: INBOX_ETH_MAINNET, LIQUIDITY_POOL_ETH_MAINNET, SWAP_ROUTER_MAINNET, ENHANCED_SWAP_ROUTER, CHALLENGE_MANAGER_MAINNET).
- **Wiring**: After deploy, the script calls `LiquidityPoolETH.authorizeRelease(coordinator)` and `EnhancedSwapRouter.grantRole(COORDINATOR_ROLE, coordinator)`.
- **.env**: Set `DUAL_ROUTER_BRIDGE_SWAP_COORDINATOR` to the deployed address.

View File

@@ -112,6 +112,38 @@ ONEINCH_ROUTER=0x1111111254EEB25477B68fb85Ed929f73A960582
# Add more pool IDs as needed
```
## Dodoex PMM / Full Swappable (Chains 138, 651940)
For PMM coverage of all tokens and swap+bridge+swap flow:
```bash
# Per-chain DODO (set for each chain)
CHAIN_138_DODO_POOL_MANAGER=0x...
CHAIN_138_DODO_VENDING_MACHINE=0x...
CHAIN_651940_DODO_POOL_MANAGER=0x...
CHAIN_651940_DODO_VENDING_MACHINE=0x...
# Token coverage script (create-all-dodo-pools-from-token-api.sh)
TOKEN_AGGREGATION_API_URL=http://localhost:3000
CHAIN_ID=138
QUOTE_TOKEN_ADDRESS=0x... # WETH or canonical stable per chain
DODO_PMM_INTEGRATION_ADDRESS=0x...
ENHANCED_SWAP_ROUTER_ADDRESS=0x...
UNIVERSAL_ASSET_REGISTRY_ADDRESS=0x...
RPC_URL=...
PRIVATE_KEY=0x...
# Quote service (swap+bridge+swap)
ENHANCED_SWAP_ROUTER_ADDRESS=0x... # Source chain router
DESTINATION_RPC_URL=...
DESTINATION_SWAP_ROUTER_ADDRESS=0x...
# SwapBridgeSwapCoordinator (atomic swap then bridge)
SWAP_BRIDGE_SWAP_COORDINATOR=0x...
```
Run pool creation for all tokens: `scripts/create-all-dodo-pools-from-token-api.sh` (use `DRY_RUN=true` to preview). Ensure CCIP router and chain selectors are set for 138, 651940, and target chains; LINK funded for bridge contracts.
## Service Configuration
### Market Reporting Service