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

@@ -0,0 +1,79 @@
# Send 20M cUSDT and cUSDC Script
## Overview
This script sends 20,000,000 cUSDT and 20,000,000 cUSDC tokens to the specified wallet address.
**Recipient Address:** `0x4207aA9aC89B8bF4795dbAbBbE17fdd224E7947C`
## Usage
```bash
cd /home/intlc/projects/proxmox/smom-dbis-138
./scripts/send-20m-tokens.sh
```
## How It Works
1. **Checks Deployer Balance**: Verifies if the deployer address has sufficient tokens
2. **Smart Minting/Transfer**:
- If deployer has sufficient balance: Transfers tokens from deployer to recipient
- If deployer has insufficient balance: Mints tokens directly to recipient (requires owner role)
3. **Verification**: Confirms the transfers by checking recipient balances
## Token Details
- **cUSDT Address**: `0x93E66202A11B1772E55407B32B44e5Cd8eda7f22`
- **cUSDC Address**: `0xf22258f57794CC8E06237084b353Ab30fFfa640b`
- **Amount**: 20,000,000 tokens each (20000000000000 in base units with 6 decimals)
## Prerequisites
1. `.env` file must exist in the project root with:
- `PRIVATE_KEY`: Private key of the deployer/owner
- `RPC_URL` or `RPC_URL_138`: RPC endpoint URL
- `COMPLIANT_USDT_ADDRESS`: cUSDT contract address (optional, has defaults)
- `COMPLIANT_USDC_ADDRESS`: cUSDC contract address (optional, has defaults)
2. The deployer address must be the owner of both token contracts (for minting)
3. RPC endpoint must be accessible
## Expected Output
```
╔══════════════════════════════════════════════════════════════╗
║ Send 20M cUSDT and cUSDC ║
╚══════════════════════════════════════════════════════════════╝
Deployer Address: 0x...
Recipient Address: 0x4207aA9aC89B8bF4795dbAbBbE17fdd224E7947C
Amount: 20,000,000 tokens (each)
Checking balances...
Deployer cUSDT Balance: X tokens
Deployer cUSDC Balance: X tokens
Minting 20M cUSDT to recipient...
✓ cUSDT mint successful
Transaction Hash: 0x...
Minting 20M cUSDC to recipient...
✓ cUSDC mint successful
Transaction Hash: 0x...
Verifying transfers...
Recipient cUSDT Balance: 20000000.00 tokens
Recipient cUSDC Balance: 20000000.00 tokens
╔══════════════════════════════════════════════════════════════╗
║ Transfers Complete! ║
╚══════════════════════════════════════════════════════════════╝
```
## Notes
- The script uses `cast` from Foundry
- Gas price is set to 20 gwei (20000000000)
- Transactions use legacy format
- Script will exit on any error

View File

@@ -50,6 +50,16 @@ contract InitializeRegistry is Script {
address(0x200)
);
// Register Etherlink (Tezos EVM L2)
registry.registerDestination(
42793,
"Etherlink Mainnet",
1,
1800,
10,
address(0x200)
);
// Register XRPL
registry.registerDestination(
0,
@@ -60,13 +70,25 @@ contract InitializeRegistry is Script {
address(0x200)
);
// Register native ETH token
uint256[] memory allDestinations = new uint256[](5);
// Register Tezos L1 (non-EVM; chainId 1 in registry for non-EVM slot)
registry.registerDestination(
1,
"Tezos-Mainnet",
1,
300,
20,
address(0x200)
);
// Register native ETH token (Polygon, Optimism, Base, Arbitrum, Etherlink, XRPL, Tezos)
uint256[] memory allDestinations = new uint256[](7);
allDestinations[0] = 137;
allDestinations[1] = 10;
allDestinations[2] = 8453;
allDestinations[3] = 42161;
allDestinations[4] = 0;
allDestinations[4] = 42793;
allDestinations[5] = 0;
allDestinations[6] = 1;
registry.registerToken(
address(0), // Native ETH

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# B7: Register ISO-4217W tokens with BridgeRegistry (BRG-ISO)
# Requires: PRIVATE_KEY, RPC_URL_138, USDW_ADDRESS, EURW_ADDRESS, BRIDGE_REGISTRY_ADDRESS
set -euo pipefail
cd "$(dirname "$0")/../.."
source .env 2>/dev/null || true
: "${PRIVATE_KEY:?PRIVATE_KEY required}"
: "${RPC_URL_138:?RPC_URL_138 required}"
: "${BRIDGE_REGISTRY_ADDRESS:?BRIDGE_REGISTRY_ADDRESS required}"
echo "Registering ISO-4217W tokens (USDW, EURW, GBPW) with BridgeRegistry..."
echo "Use cast send to call bridgeRegistry.registerToken(token, ...)"
echo "Note: Include 42793 (Etherlink) and 1 (Tezos L1) in allowedDestinations when registering tokens for Tezos bridging."

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env bash
# B6: Register Vault deposit tokens with BridgeRegistry (BRG-VLT)
# Requires: PRIVATE_KEY, RPC_URL_138, VAULT_BRIDGE_INTEGRATION_ADDRESS, BRIDGE_REGISTRY_ADDRESS
# Run after deploying Vault system and VaultBridgeIntegration
set -euo pipefail
cd "$(dirname "$0")/../.."
source .env 2>/dev/null || true
: "${PRIVATE_KEY:?PRIVATE_KEY required}"
: "${RPC_URL_138:?RPC_URL_138 required}"
: "${VAULT_BRIDGE_INTEGRATION_ADDRESS:?VAULT_BRIDGE_INTEGRATION_ADDRESS required}"
echo "Registering Vault deposit tokens with BridgeRegistry..."
echo "VaultBridgeIntegration: $VAULT_BRIDGE_INTEGRATION_ADDRESS"
echo "Use cast send to call registerDepositToken(depositToken, chainIds, min, max, riskLevel, feeBps)"
echo "Note: defaultDestinations in VaultBridgeIntegration include 42793 (Etherlink); for Tezos L1 include chainId 1 in allowedDestinations when registering tokens."

View File

@@ -0,0 +1,44 @@
/**
* Deploy CCIPLogger to a configurable network (Mainnet, BSC, Polygon, Gnosis, Cronos).
* Usage: NETWORK=bsc npx hardhat run scripts/ccip-deployment/deploy-ccip-logger-multichain.js
*
* Prerequisites:
* - contracts/ccip-integration/CCIPLogger.sol must exist (currently missing - see TASK12_CCIP_LOGGER_STATUS.md)
* - PRIVATE_KEY in .env
* - Chain-specific RPC and CCIP Router in .env (e.g. CCIP_BSC_ROUTER for BSC)
*/
require("dotenv").config();
const network = process.env.NETWORK || process.env.HARDHAT_NETWORK || "mainnet";
const ROUTERS = {
mainnet: process.env.CCIP_ETH_ROUTER || "0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D",
bsc: process.env.CCIP_BSC_ROUTER || "",
polygon: process.env.CCIP_POLYGON_ROUTER || "",
gnosis: process.env.CCIP_GNOSIS_ROUTER || "",
cronos: process.env.CCIP_CRONOS_ROUTER || "0xE26B0A098D861d5C7d9434aD471c0572Ca6EAa67",
};
async function main() {
const { ethers } = require("hardhat");
const routerAddress = ROUTERS[network] || ROUTERS.mainnet;
if (!routerAddress) {
throw new Error(`CCIP Router not configured for ${network}. Set CCIP_${network.toUpperCase()}_ROUTER in .env`);
}
const authorizedSigner = process.env.AUTHORIZED_SIGNER || ethers.ZeroAddress;
const sourceChainSelector = process.env.CHAIN138_SELECTOR || "0x000000000000008a";
const [deployer] = await ethers.getSigners();
console.log(`Deploying CCIPLogger to ${network}...`);
console.log(" Account:", deployer.address);
console.log(" Balance:", (await ethers.provider.getBalance(deployer.address)).toString());
console.log(" Router:", routerAddress);
const CCIPLogger = await ethers.getContractFactory("CCIPLogger");
const logger = await CCIPLogger.deploy(routerAddress, authorizedSigner, sourceChainSelector);
await logger.waitForDeployment();
const addr = await logger.getAddress();
console.log("\n✅ CCIPLogger deployed:", addr);
console.log("\nNext: npx hardhat verify --network", network, addr, `"${routerAddress}"`, `"${authorizedSigner}"`, `"${sourceChainSelector}"`);
}
main().then(() => process.exit(0)).catch((e) => { console.error(e); process.exit(1); });

View File

@@ -31,9 +31,12 @@ async function main() {
const CCIPTxReporter = await ethers.getContractFactory("CCIPTxReporter");
console.log("\nDeploying CCIPTxReporter...");
const selectorU64 = typeof destChainSelector === "string" && destChainSelector.startsWith("0x")
? BigInt(destChainSelector)
: BigInt(destChainSelector);
const reporter = await CCIPTxReporter.deploy(
routerAddress,
destChainSelector,
selectorU64,
destReceiver
);

View File

@@ -0,0 +1,214 @@
#!/bin/bash
# Complete Checklist for AUSDT on ALL MAINNET (ChainID 651940)
# Usage: ./check-ausdt-all-mainnet.sh
# Don't exit on error - we want to continue checking
set +e
# Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Configuration
CHAIN_ID=651940
AUSDT_ADDRESS="0x015B1897Ed5279930bC2Be46F661894d219292A6"
RPC_URL="${RPC_URL_651940:-https://mainnet-rpc.alltra.global}"
EXPLORER_URL="https://alltra.global"
# Counters
PASSED=0
FAILED=0
WARNINGS=0
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; ((PASSED++)); }
log_error() { echo -e "${RED}[✗]${NC} $1"; ((FAILED++)); }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; ((WARNINGS++)); }
log_section() { echo -e "\n${CYAN}══════════════════════════════════════════════════════════════${NC}"; echo -e "${CYAN}$1${NC}"; echo -e "${CYAN}══════════════════════════════════════════════════════════════${NC}\n"; }
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ AUSDT on ALL MAINNET - Complete Checklist ║${NC}"
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${BLUE}Token Address:${NC} $AUSDT_ADDRESS"
echo -e "${BLUE}Chain ID:${NC} $CHAIN_ID (ALL Mainnet)"
echo -e "${BLUE}RPC URL:${NC} $RPC_URL"
echo -e "${BLUE}Explorer:${NC} $EXPLORER_URL"
echo ""
# ============================================================================
# 1. RPC CONNECTIVITY
# ============================================================================
log_section "1. RPC Connectivity Check"
log_info "Testing RPC endpoint connectivity..."
if curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \
--max-time 10 "$RPC_URL" > /dev/null 2>&1; then
log_success "RPC endpoint is accessible"
# Verify chain ID (with timeout)
CHAIN_ID_RESPONSE=$(timeout 10 curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \
--max-time 10 "$RPC_URL" 2>/dev/null | python3 -c "import sys, json; print(json.load(sys.stdin).get('result', ''))" 2>/dev/null || echo "")
if [ -n "$CHAIN_ID_RESPONSE" ] && [ "$CHAIN_ID_RESPONSE" != "" ]; then
CHAIN_ID_DEC=$(printf "%d" "$CHAIN_ID_RESPONSE" 2>/dev/null || echo "0")
if [ "$CHAIN_ID_DEC" = "$CHAIN_ID" ]; then
log_success "Chain ID matches: $CHAIN_ID"
else
log_warn "Chain ID mismatch: Expected $CHAIN_ID, got $CHAIN_ID_DEC (may be hex format)"
fi
else
log_warn "Could not verify chain ID (RPC may be slow)"
fi
else
log_error "RPC endpoint is not accessible"
fi
# ============================================================================
# 2. CONTRACT DEPLOYMENT
# ============================================================================
log_section "2. Contract Deployment Verification"
log_info "Checking if contract is deployed..."
CONTRACT_CODE=$(timeout 15 cast code "$AUSDT_ADDRESS" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$CONTRACT_CODE" ] && [ "$CONTRACT_CODE" != "0x" ] && [ "$CONTRACT_CODE" != "" ]; then
CODE_SIZE=$(echo "$CONTRACT_CODE" | wc -c)
if [ "$CODE_SIZE" -gt 10 ]; then
log_success "Contract is deployed (code size: $CODE_SIZE bytes)"
else
log_error "Contract code is empty or invalid"
fi
else
log_error "Contract is not deployed or not accessible"
fi
# ============================================================================
# 3. TOKEN METADATA
# ============================================================================
log_section "3. Token Metadata Verification"
log_info "Fetching token name..."
TOKEN_NAME=$(timeout 15 cast call "$AUSDT_ADDRESS" "name()(string)" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$TOKEN_NAME" ] && [ "$TOKEN_NAME" != "" ]; then
log_success "Token Name: $TOKEN_NAME"
else
log_error "Failed to fetch token name"
fi
log_info "Fetching token symbol..."
TOKEN_SYMBOL=$(timeout 15 cast call "$AUSDT_ADDRESS" "symbol()(string)" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$TOKEN_SYMBOL" ] && [ "$TOKEN_SYMBOL" != "" ]; then
# Remove quotes if present
TOKEN_SYMBOL_CLEAN=$(echo "$TOKEN_SYMBOL" | tr -d '"')
log_success "Token Symbol: $TOKEN_SYMBOL_CLEAN"
if [ "$TOKEN_SYMBOL_CLEAN" = "AUSDT" ]; then
log_success "Symbol matches expected: AUSDT"
else
log_warn "Symbol mismatch: Expected AUSDT, got $TOKEN_SYMBOL_CLEAN"
fi
else
log_error "Failed to fetch token symbol"
fi
log_info "Fetching token decimals..."
TOKEN_DECIMALS=$(timeout 15 cast call "$AUSDT_ADDRESS" "decimals()(uint8)" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$TOKEN_DECIMALS" ]; then
DECIMALS_DEC=$(printf "%d" "$TOKEN_DECIMALS" 2>/dev/null || echo "0")
log_success "Token Decimals: $DECIMALS_DEC"
if [ "$DECIMALS_DEC" = "18" ]; then
log_success "Decimals match expected: 18"
else
log_warn "Decimals mismatch: Expected 18, got $DECIMALS_DEC"
fi
else
log_error "Failed to fetch token decimals"
fi
# ============================================================================
# 4. TOKEN SUPPLY
# ============================================================================
log_section "4. Token Supply Information"
log_info "Fetching total supply..."
TOTAL_SUPPLY=$(timeout 15 cast call "$AUSDT_ADDRESS" "totalSupply()(uint256)" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$TOTAL_SUPPLY" ] && [ "$TOTAL_SUPPLY" != "0x0" ] && [ "$TOTAL_SUPPLY" != "0" ]; then
SUPPLY_DEC=$(printf "%d" "$TOTAL_SUPPLY" 2>/dev/null || echo "0")
if [ "$DECIMALS_DEC" = "18" ]; then
SUPPLY_DISPLAY=$(echo "scale=2; $SUPPLY_DEC / 1000000000000000000" | bc 2>/dev/null || echo "$SUPPLY_DEC")
log_success "Total Supply: $SUPPLY_DISPLAY AUSDT"
else
log_success "Total Supply: $SUPPLY_DEC (raw)"
fi
else
log_warn "Total supply is zero or could not be fetched"
fi
# ============================================================================
# 5. ERC-20 FUNCTIONALITY
# ============================================================================
log_section "5. ERC-20 Functionality Check"
log_info "Testing balanceOf function..."
BALANCE=$(timeout 15 cast call "$AUSDT_ADDRESS" "balanceOf(address)(uint256)" "0x0000000000000000000000000000000000000000" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$BALANCE" ]; then
log_success "balanceOf() function works"
else
log_error "balanceOf() function failed"
fi
log_info "Testing allowance function..."
ALLOWANCE=$(timeout 15 cast call "$AUSDT_ADDRESS" "allowance(address,address)(uint256)" "0x0000000000000000000000000000000000000000" "0x0000000000000000000000000000000000000000" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$ALLOWANCE" ]; then
log_success "allowance() function works"
else
log_error "allowance() function failed"
fi
# ============================================================================
# 6. TOKEN LIST VERIFICATION
# ============================================================================
log_section "6. Token List Integration"
TOKEN_LIST_FILE="token-lists/lists/all-mainnet.tokenlist.json"
if [ -f "$TOKEN_LIST_FILE" ]; then
log_success "Token list file exists: $TOKEN_LIST_FILE"
if grep -q "$AUSDT_ADDRESS" "$TOKEN_LIST_FILE"; then
log_success "AUSDT address found in token list"
else
log_error "AUSDT address not found in token list"
fi
else
log_error "Token list file not found: $TOKEN_LIST_FILE"
fi
# ============================================================================
# SUMMARY
# ============================================================================
log_section "Checklist Summary"
echo ""
echo -e "${CYAN}Results:${NC}"
echo -e " ${GREEN}✓ Passed:${NC} $PASSED"
echo -e " ${RED}✗ Failed:${NC} $FAILED"
echo -e " ${YELLOW}⚠ Warnings:${NC} $WARNINGS"
echo ""
if [ $FAILED -eq 0 ]; then
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ All Critical Checks Passed! ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
exit 0
else
echo -e "${RED}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}║ Some Checks Failed - Review Above ║${NC}"
echo -e "${RED}╚══════════════════════════════════════════════════════════════╝${NC}"
exit 1
fi

View File

@@ -0,0 +1,281 @@
#!/bin/bash
# Complete MetaMask Integration Check
# Verifies decimals, balances, pricing, and volumes for MetaMask
# Usage: ./check-metamask-integration.sh
set +e
# Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Configuration
CHAIN_ID=138
RPC_URL="${RPC_URL:-${RPC_URL_138:-http://192.168.11.211:8545}}"
ORACLE_ADDRESS="0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6"
# Token addresses
WETH9="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
WETH10="0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f"
CUSDT="0x93E66202A11B1772E55407B32B44e5Cd8eda7f22"
CUSDC="0xf22258f57794CC8E06237084b353Ab30fFfa640b"
# Counters
PASSED=0
FAILED=0
WARNINGS=0
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; ((PASSED++)); }
log_error() { echo -e "${RED}[✗]${NC} $1"; ((FAILED++)); }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; ((WARNINGS++)); }
log_section() { echo -e "\n${CYAN}══════════════════════════════════════════════════════════════${NC}"; echo -e "${CYAN}$1${NC}"; echo -e "${CYAN}══════════════════════════════════════════════════════════════${NC}\n"; }
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ MetaMask Integration - Complete Verification ║${NC}"
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${BLUE}Chain ID:${NC} $CHAIN_ID"
echo -e "${BLUE}RPC URL:${NC} $RPC_URL"
echo ""
# ============================================================================
# 1. TOKEN DECIMALS VERIFICATION
# ============================================================================
log_section "1. Token Decimals Verification"
declare -A TOKENS=(
["WETH9"]="$WETH9:18"
["WETH10"]="$WETH10:18"
["cUSDT"]="$CUSDT:6"
["cUSDC"]="$CUSDC:6"
)
TOKEN_LIST_FILE="token-lists/lists/dbis-138.tokenlist.json"
METAMASK_LIST_FILE="docs/04-configuration/metamask/METAMASK_TOKEN_LIST.json"
for TOKEN_NAME in "${!TOKENS[@]}"; do
IFS=':' read -r ADDRESS EXPECTED_DEC <<< "${TOKENS[$TOKEN_NAME]}"
log_info "Checking $TOKEN_NAME ($ADDRESS)..."
# Check on-chain decimals
ONCHAIN_DEC=$(timeout 15 cast call "$ADDRESS" "decimals()(uint8)" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$ONCHAIN_DEC" ]; then
DEC_DEC=$(printf "%d" "$ONCHAIN_DEC" 2>/dev/null || echo "0")
if [ "$DEC_DEC" = "$EXPECTED_DEC" ]; then
log_success "$TOKEN_NAME: On-chain decimals correct ($DEC_DEC)"
else
log_warn "$TOKEN_NAME: On-chain decimals mismatch (got $DEC_DEC, expected $EXPECTED_DEC)"
fi
else
log_error "$TOKEN_NAME: Failed to fetch on-chain decimals"
fi
# Check token list decimals
if [ -f "$TOKEN_LIST_FILE" ]; then
LIST_DEC=$(grep -A 10 "\"$ADDRESS\"" "$TOKEN_LIST_FILE" 2>/dev/null | grep "decimals" | head -1 | grep -oE "[0-9]+" || echo "")
if [ -n "$LIST_DEC" ] && [ "$LIST_DEC" = "$EXPECTED_DEC" ]; then
log_success "$TOKEN_NAME: Token list decimals correct ($LIST_DEC)"
elif [ -n "$LIST_DEC" ]; then
log_warn "$TOKEN_NAME: Token list decimals mismatch (got $LIST_DEC, expected $EXPECTED_DEC)"
else
log_warn "$TOKEN_NAME: Not found in token list"
fi
fi
# Check MetaMask token list
if [ -f "$METAMASK_LIST_FILE" ]; then
META_DEC=$(grep -A 10 "\"$ADDRESS\"" "$METAMASK_LIST_FILE" 2>/dev/null | grep "decimals" | head -1 | grep -oE "[0-9]+" || echo "")
if [ -n "$META_DEC" ] && [ "$META_DEC" = "$EXPECTED_DEC" ]; then
log_success "$TOKEN_NAME: MetaMask list decimals correct ($META_DEC)"
elif [ -n "$META_DEC" ]; then
log_warn "$TOKEN_NAME: MetaMask list decimals mismatch (got $META_DEC, expected $EXPECTED_DEC)"
fi
fi
echo ""
done
# ============================================================================
# 2. BALANCE DISPLAY VERIFICATION
# ============================================================================
log_section "2. Balance Display Verification"
log_info "Testing balanceOf for sample addresses..."
# Test with zero address
TEST_ADDRESS="0x0000000000000000000000000000000000000000"
for TOKEN_NAME in "${!TOKENS[@]}"; do
IFS=':' read -r ADDRESS EXPECTED_DEC <<< "${TOKENS[$TOKEN_NAME]}"
BALANCE=$(timeout 15 cast call "$ADDRESS" "balanceOf(address)(uint256)" "$TEST_ADDRESS" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$BALANCE" ]; then
log_success "$TOKEN_NAME: balanceOf() function works"
else
log_error "$TOKEN_NAME: balanceOf() function failed"
fi
done
# ============================================================================
# 3. ORACLE PRICE FEED VERIFICATION
# ============================================================================
log_section "3. Oracle Price Feed Verification"
log_info "Checking oracle contract..."
ORACLE_DATA=$(timeout 15 cast call "$ORACLE_ADDRESS" "latestRoundData()" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$ORACLE_DATA" ] && [ "$ORACLE_DATA" != "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ]; then
# Extract answer (second field)
ANSWER_HEX=$(echo "$ORACLE_DATA" | cut -c 131-194)
ANSWER_DEC=$(printf "%d" "0x$ANSWER_HEX" 2>/dev/null || echo "0")
if [ "$ANSWER_DEC" != "0" ] && [ "$ANSWER_DEC" -gt 0 ]; then
PRICE=$(echo "scale=2; $ANSWER_DEC / 100000000" | bc 2>/dev/null || echo "0")
log_success "Oracle has price data: ETH/USD = \$$PRICE"
# Check update timestamp
UPDATED_AT_HEX=$(echo "$ORACLE_DATA" | cut -c 259-322)
UPDATED_AT=$(printf "%d" "0x$UPDATED_AT_HEX" 2>/dev/null || echo "0")
if [ "$UPDATED_AT" != "0" ]; then
CURRENT_TIME=$(date +%s)
AGE=$((CURRENT_TIME - UPDATED_AT))
if [ $AGE -lt 300 ]; then
log_success "Oracle price is fresh (updated $AGE seconds ago)"
else
MINUTES=$((AGE / 60))
log_warn "Oracle price may be stale (updated $MINUTES minutes ago)"
fi
fi
else
log_error "Oracle price is zero (needs update)"
fi
else
log_error "Oracle contract returns zero or empty data"
fi
log_info ""
log_warn "IMPORTANT: MetaMask does NOT automatically query oracle contracts"
log_info "MetaMask uses CoinGecko API for USD prices (requires token listing)"
# ============================================================================
# 4. METAMASK PRICE SOURCE VERIFICATION
# ============================================================================
log_section "4. MetaMask Price Source Verification"
log_info "MetaMask Price Sources (in order):"
echo " 1. CoinGecko API (primary) - requires token listing"
echo " 2. Token Lists - limited price metadata support"
echo " 3. Oracle Contracts - NOT automatically queried"
echo ""
log_info "Checking CoinGecko listing status..."
# Check if tokens are likely on CoinGecko
TOKENS_TO_CHECK=("ethereum" "tether" "usd-coin")
for TOKEN_ID in "${TOKENS_TO_CHECK[@]}"; do
COINGECKO_DATA=$(curl -s "https://api.coingecko.com/api/v3/simple/price?ids=$TOKEN_ID&vs_currencies=usd" --max-time 5 2>/dev/null || echo "")
if echo "$COINGECKO_DATA" | grep -q "usd"; then
log_success "CoinGecko API accessible for $TOKEN_ID"
else
log_warn "CoinGecko API may not have data for $TOKEN_ID"
fi
done
log_info ""
log_warn "Note: cUSDT and cUSDC are NOT listed on CoinGecko yet"
log_info "See: docs/04-configuration/coingecko/COINGECKO_SUBMISSION_GUIDE.md"
# ============================================================================
# 5. VOLUME DATA VERIFICATION
# ============================================================================
log_section "5. Volume Data Verification"
log_info "MetaMask Volume Data Sources:"
echo " - CoinGecko API (if token is listed)"
echo " - Token Lists (limited support)"
echo " - Oracle contracts (NOT used by MetaMask)"
echo ""
log_warn "MetaMask does NOT display volume data from oracles"
log_info "Volume data comes from CoinGecko or external APIs"
# Check if token aggregation service exists
TOKEN_AGG_SERVICE="smom-dbis-138/services/token-aggregation"
if [ -d "$TOKEN_AGG_SERVICE" ]; then
log_success "Token aggregation service exists"
log_info " Service can aggregate volume data from multiple sources"
log_info " But MetaMask doesn't query this service directly"
else
log_warn "Token aggregation service not found"
fi
# ============================================================================
# 6. TOKEN LIST HOSTING VERIFICATION
# ============================================================================
log_section "6. Token List Hosting Verification"
TOKEN_LIST_URL="https://raw.githubusercontent.com/Defi-Oracle-Meta-Blockchain/metamask-integration/main/config/token-list.json"
log_info "Checking hosted token list..."
if curl -s -I "$TOKEN_LIST_URL" --max-time 5 | head -1 | grep -q "200\|301\|302"; then
log_success "Token list is hosted and accessible"
log_info " URL: $TOKEN_LIST_URL"
# Check if list has correct decimals
LIST_CONTENT=$(curl -s "$TOKEN_LIST_URL" --max-time 5 2>/dev/null || echo "")
if echo "$LIST_CONTENT" | grep -q "\"decimals\": 18"; then
log_success "Token list includes 18 decimals entries"
fi
if echo "$LIST_CONTENT" | grep -q "\"decimals\": 6"; then
log_success "Token list includes 6 decimals entries"
fi
else
log_warn "Token list may not be accessible at hosted URL"
fi
# ============================================================================
# SUMMARY
# ============================================================================
log_section "Verification Summary"
echo ""
echo -e "${CYAN}Results:${NC}"
echo -e " ${GREEN}✓ Passed:${NC} $PASSED"
echo -e " ${RED}✗ Failed:${NC} $FAILED"
echo -e " ${YELLOW}⚠ Warnings:${NC} $WARNINGS"
echo ""
echo -e "${CYAN}Key Findings:${NC}"
echo ""
echo "1. ${GREEN}Decimals:${NC} Token lists override on-chain decimals"
echo " - WETH9: Contract returns 0, but token list has 18 ✅"
echo " - cUSDT/cUSDC: Both contract and list have 6 ✅"
echo ""
echo "2. ${YELLOW}Pricing:${NC} MetaMask uses CoinGecko, NOT oracles"
echo " - Oracle exists but MetaMask doesn't query it"
echo " - cUSDT/cUSDC need CoinGecko listing for USD display"
echo ""
echo "3. ${YELLOW}Volumes:${NC} MetaMask doesn't display volume from oracles"
echo " - Volume data comes from CoinGecko/external APIs"
echo " - Oracle contracts don't provide volume data"
echo ""
echo "4. ${GREEN}Balances:${NC} ERC-20 functions work correctly"
echo " - balanceOf() works for all tokens"
echo " - Display depends on correct decimals in token list"
echo ""
if [ $FAILED -eq 0 ]; then
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ All Critical Checks Passed! ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
exit 0
else
echo -e "${YELLOW}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${YELLOW}║ Some Checks Need Attention ║${NC}"
echo -e "${YELLOW}╚══════════════════════════════════════════════════════════════╝${NC}"
exit 1
fi

View File

@@ -0,0 +1,171 @@
#!/bin/bash
# Check Oracle Publisher Service Status
# Usage: ./check-oracle-publisher-status.sh
set -e
# Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.10}"
VMID=3500
ORACLE_ADDRESS="0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6"
RPC_URL="${RPC_URL:-${RPC_URL_138:-http://192.168.11.211:8545}}"
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Oracle Publisher Service Status Check ║${NC}"
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
# Check if container exists
echo -e "${YELLOW}1. Checking if container (VMID $VMID) exists...${NC}"
if ssh "root@$PROXMOX_HOST" "pct list | grep -q '^[[:space:]]*$VMID'" 2>/dev/null; then
CONTAINER_STATUS=$(ssh "root@$PROXMOX_HOST" "pct status $VMID 2>/dev/null | awk '{print \$2}'" || echo "unknown")
echo -e "${GREEN}✓ Container exists (Status: $CONTAINER_STATUS)${NC}"
else
echo -e "${RED}✗ Container VMID $VMID not found${NC}"
echo ""
echo "Container needs to be created. See documentation:"
echo " docs/04-configuration/metamask/ORACLE_PRICE_FEED_SETUP.md"
exit 1
fi
echo ""
# Check service status
echo -e "${YELLOW}2. Checking oracle-publisher service status...${NC}"
SERVICE_STATUS=$(ssh "root@$PROXMOX_HOST" "pct exec $VMID -- systemctl is-active oracle-publisher.service 2>/dev/null || echo 'inactive'" 2>&1)
if [ "$SERVICE_STATUS" = "active" ]; then
echo -e "${GREEN}✓ Service is active${NC}"
# Check if service is enabled
ENABLED=$(ssh "root@$PROXMOX_HOST" "pct exec $VMID -- systemctl is-enabled oracle-publisher.service 2>/dev/null || echo 'disabled'" 2>&1)
if [ "$ENABLED" = "enabled" ]; then
echo -e "${GREEN}✓ Service is enabled (will start on boot)${NC}"
else
echo -e "${YELLOW}⚠ Service is not enabled (won't start on boot)${NC}"
fi
else
echo -e "${RED}✗ Service is $SERVICE_STATUS${NC}"
echo ""
echo "To start the service:"
echo " ssh root@$PROXMOX_HOST \"pct exec $VMID -- systemctl start oracle-publisher\""
echo " ssh root@$PROXMOX_HOST \"pct exec $VMID -- systemctl enable oracle-publisher\""
fi
echo ""
# Check configuration file
echo -e "${YELLOW}3. Checking configuration file...${NC}"
if ssh "root@$PROXMOX_HOST" "pct exec $VMID -- test -f /opt/oracle-publisher/.env" 2>/dev/null; then
echo -e "${GREEN}✓ Configuration file exists${NC}"
# Check key configuration variables
echo " Checking key variables..."
ENV_VARS=("ORACLE_ADDRESS" "AGGREGATOR_ADDRESS" "RPC_URL" "CHAIN_ID" "PRIVATE_KEY" "UPDATE_INTERVAL")
for VAR in "${ENV_VARS[@]}"; do
VALUE=$(ssh "root@$PROXMOX_HOST" "pct exec $VMID -- grep '^${VAR}=' /opt/oracle-publisher/.env 2>/dev/null | cut -d= -f2-" || echo "")
if [ -n "$VALUE" ]; then
if [ "$VAR" = "PRIVATE_KEY" ]; then
echo -e " ${GREEN}${NC} $VAR = [HIDDEN]"
else
echo -e " ${GREEN}${NC} $VAR = $VALUE"
fi
else
echo -e " ${RED}${NC} $VAR not set"
fi
done
else
echo -e "${RED}✗ Configuration file not found at /opt/oracle-publisher/.env${NC}"
fi
echo ""
# Check recent logs
echo -e "${YELLOW}4. Checking recent service logs (last 10 lines)...${NC}"
RECENT_LOGS=$(ssh "root@$PROXMOX_HOST" "pct exec $VMID -- journalctl -u oracle-publisher.service -n 10 --no-pager 2>/dev/null" || echo "")
if [ -n "$RECENT_LOGS" ]; then
echo "$RECENT_LOGS" | while IFS= read -r line; do
if echo "$line" | grep -qiE "(error|failed|exception)"; then
echo -e " ${RED}$line${NC}"
elif echo "$line" | grep -qiE "(price|update|success)"; then
echo -e " ${GREEN}$line${NC}"
else
echo " $line"
fi
done
else
echo -e "${YELLOW}⚠ No recent logs found${NC}"
fi
echo ""
# Check oracle contract price
echo -e "${YELLOW}5. Checking oracle contract price data...${NC}"
ORACLE_DATA=$(cast call "$ORACLE_ADDRESS" "latestRoundData()" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$ORACLE_DATA" ]; then
# Parse the response (format: roundId, answer, startedAt, updatedAt, answeredInRound)
# Extract answer (second field, bytes 131-194)
ANSWER_HEX=$(echo "$ORACLE_DATA" | cut -c 131-194)
if [ "$ANSWER_HEX" != "00000000000000000000000000000000000000000000000000000000" ]; then
# Convert hex to decimal
ANSWER_DEC=$(printf "%d" "0x$ANSWER_HEX" 2>/dev/null || echo "0")
# Handle signed integer (if > 2^255, it's negative)
if [ "$ANSWER_DEC" -gt 9223372036854775807 ] 2>/dev/null; then
ANSWER_DEC=$((ANSWER_DEC - 18446744073709551616))
fi
# Convert from 8 decimals to USD
PRICE=$(echo "scale=2; $ANSWER_DEC / 100000000" | bc 2>/dev/null || echo "0")
if [ "$PRICE" != "0" ] && [ "$PRICE" != "0.00" ]; then
echo -e "${GREEN}✓ Oracle has price data${NC}"
echo " ETH/USD Price: \$$PRICE"
# Extract updatedAt (fourth field)
UPDATED_AT_HEX=$(echo "$ORACLE_DATA" | cut -c 259-322)
UPDATED_AT=$(printf "%d" "0x$UPDATED_AT_HEX" 2>/dev/null || echo "0")
if [ "$UPDATED_AT" != "0" ]; then
CURRENT_TIME=$(date +%s)
AGE=$((CURRENT_TIME - UPDATED_AT))
if [ $AGE -lt 300 ]; then
echo -e "${GREEN}✓ Price updated $AGE seconds ago (fresh)${NC}"
elif [ $AGE -lt 3600 ]; then
MINUTES=$((AGE / 60))
echo -e "${YELLOW}⚠ Price updated $MINUTES minutes ago (may be stale)${NC}"
else
HOURS=$((AGE / 3600))
echo -e "${RED}✗ Price updated $HOURS hours ago (stale)${NC}"
fi
fi
else
echo -e "${RED}✗ Oracle price is zero (needs update)${NC}"
fi
else
echo -e "${RED}✗ Oracle price is zero (needs update)${NC}"
fi
else
echo -e "${RED}✗ Failed to query oracle contract${NC}"
fi
echo ""
# Summary
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Summary ║${NC}"
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo "To view full logs:"
echo " ssh root@$PROXMOX_HOST \"pct exec $VMID -- journalctl -u oracle-publisher.service -f\""
echo ""
echo "To restart service:"
echo " ssh root@$PROXMOX_HOST \"pct exec $VMID -- systemctl restart oracle-publisher\""
echo ""
echo "To update oracle manually:"
echo " cd /home/intlc/projects/proxmox/smom-dbis-138"
echo " ./scripts/update-oracle-price.sh"

View File

@@ -32,7 +32,8 @@ if [ -z "$PRIVATE_KEY" ]; then
fi
CHAIN138_RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
LINK_TOKEN="${LINK_TOKEN_138:-0x514910771AF9Ca656af840dff83E8264EcF986CA}"
# Chain 138 LINK: 0xb7721d... (deployed on 138). Mainnet canonical is 0x51491077... — do not use mainnet address when checking balance on 138.
LINK_TOKEN="${LINK_TOKEN_138:-${LINK_TOKEN_CHAIN138:-0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03}}"
WALLET_ADDRESS=$(cast wallet address --private-key "$PRIVATE_KEY")

View File

@@ -0,0 +1,179 @@
#!/usr/bin/env bash
# Create Dodoex PMM pools for all tokens on a chain using Token Aggregation API.
# Uses GET /tokens and GET /tokens/:address/pools to discover tokens and skip those already with DODO pools.
# Calls DODOPMMIntegration.createPool, EnhancedSwapRouter.setDodoPoolAddress, UniversalAssetRegistry.updatePMMPool.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
log_error() { echo -e "${RED}[✗]${NC} $1"; }
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a
source "$PROJECT_ROOT/.env"
set +a
fi
TOKEN_API_URL="${TOKEN_AGGREGATION_API_URL:-http://localhost:3000}"
CHAIN_ID="${CHAIN_ID:-138}"
RPC_URL="${RPC_URL:-}"
PRIVATE_KEY="${PRIVATE_KEY:-}"
DODO_PMM_INTEGRATION="${DODO_PMM_INTEGRATION:-${DODO_PMM_INTEGRATION_ADDRESS:-}}"
ENHANCED_SWAP_ROUTER="${ENHANCED_SWAP_ROUTER_ADDRESS:-}"
ASSET_REGISTRY="${UNIVERSAL_ASSET_REGISTRY_ADDRESS:-}"
QUOTE_TOKEN="${QUOTE_TOKEN_ADDRESS:-}"
# Default WETH for chain 138 if not set
if [ "$CHAIN_ID" = "138" ]; then
QUOTE_TOKEN="${QUOTE_TOKEN:-${WETH_ADDRESS_138:-}}"
fi
if [ "$CHAIN_ID" = "651940" ]; then
QUOTE_TOKEN="${QUOTE_TOKEN:-${WETH_ADDRESS_651940:-}}"
fi
LP_FEE_RATE="${LP_FEE_RATE:-3}"
INITIAL_PRICE="${INITIAL_PRICE:-1000000000000000000}"
K_FACTOR="${K_FACTOR:-500000000000000000}"
ENABLE_TWAP="${ENABLE_TWAP:-true}"
TWAP_VALUE="$([ "$ENABLE_TWAP" = "true" ] && echo "true" || echo "false")"
DRY_RUN="${DRY_RUN:-false}"
LIMIT="${TOKEN_PAGE_LIMIT:-500}"
for var in RPC_URL PRIVATE_KEY DODO_PMM_INTEGRATION QUOTE_TOKEN; do
eval "val=\$$var"
if [ -z "$val" ]; then
log_error "$var is not set"
exit 1
fi
done
if ! command -v jq &>/dev/null; then
log_error "jq is required. Install with: apt-get install jq / brew install jq"
exit 1
fi
if ! command -v cast &>/dev/null; then
log_error "cast (foundry) is required for on-chain calls"
exit 1
fi
log_info "========================================="
log_info "Create DODO PMM pools from Token API"
log_info "========================================="
log_info "Token API: $TOKEN_API_URL"
log_info "Chain ID: $CHAIN_ID"
log_info "Quote token (WETH/stable): $QUOTE_TOKEN"
log_info "DODO PMM Integration: $DODO_PMM_INTEGRATION"
log_info "Enhanced Swap Router: ${ENHANCED_SWAP_ROUTER:-not set}"
log_info "Asset Registry: ${ASSET_REGISTRY:-not set}"
log_info "Dry run: $DRY_RUN"
log_info ""
offset=0
total_created=0
total_skipped=0
while true; do
url="${TOKEN_API_URL}/tokens?chainId=${CHAIN_ID}&limit=${LIMIT}&offset=${offset}"
log_info "Fetching tokens: $url"
resp=$(curl -sS --fail "$url" 2>/dev/null || true)
if [ -z "$resp" ]; then
log_warn "No response or empty from Token API; check TOKEN_AGGREGATION_API_URL and that the service is running"
break
fi
count=$(echo "$resp" | jq -r '.tokens | length')
if [ -z "$count" ] || [ "$count" = "null" ] || [ "$count" -eq 0 ]; then
break
fi
for i in $(seq 0 $((count - 1))); do
token_addr=$(echo "$resp" | jq -r ".tokens[$i].address")
if [ -z "$token_addr" ] || [ "$token_addr" = "null" ]; then
continue
fi
# Skip quote token itself
if [ "$(echo "$token_addr" | tr '[:upper:]' '[:lower:]')" = "$(echo "$QUOTE_TOKEN" | tr '[:upper:]' '[:lower:]')" ]; then
continue
fi
# Check if token already has a DODO pool
pools_url="${TOKEN_API_URL}/tokens/${token_addr}/pools?chainId=${CHAIN_ID}"
pools_resp=$(curl -sS "$pools_url" 2>/dev/null || true)
has_dodo=false
if [ -n "$pools_resp" ]; then
dexes=$(echo "$pools_resp" | jq -r '.pools[].dex' 2>/dev/null || true)
if echo "$dexes" | grep -q 'dodo'; then
has_dodo=true
fi
fi
if [ "$has_dodo" = "true" ]; then
total_skipped=$((total_skipped + 1))
continue
fi
# Create pool: baseToken=token, quoteToken=QUOTE_TOKEN (e.g. WETH)
if [ "$DRY_RUN" = "true" ]; then
log_info "[DRY RUN] Would createPool base=$token_addr quote=$QUOTE_TOKEN"
total_created=$((total_created + 1))
continue
fi
if ! pool_addr=$(cast call "$DODO_PMM_INTEGRATION" "pools(address,address)(address)" "$token_addr" "$QUOTE_TOKEN" --rpc-url "$RPC_URL" 2>/dev/null | cast --to-addr 2>/dev/null); then
pool_addr=""
fi
if [ -n "$pool_addr" ] && [ "$pool_addr" != "0x0000000000000000000000000000000000000000" ]; then
log_warn "Pool already exists for $token_addr / $QUOTE_TOKEN: $pool_addr"
total_skipped=$((total_skipped + 1))
continue
fi
log_info "Creating pool: base=$token_addr quote=$QUOTE_TOKEN"
if cast send "$DODO_PMM_INTEGRATION" \
"createPool(address,address,uint256,uint256,uint256,bool)" \
"$token_addr" \
"$QUOTE_TOKEN" \
"$LP_FEE_RATE" \
"$INITIAL_PRICE" \
"$K_FACTOR" \
"$TWAP_VALUE" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
-q 2>/dev/null; then
pool_addr=$(cast call "$DODO_PMM_INTEGRATION" "pools(address,address)(address)" "$token_addr" "$QUOTE_TOKEN" --rpc-url "$RPC_URL" | cast --to-addr)
log_success "Pool created: $pool_addr"
if [ -n "$ENHANCED_SWAP_ROUTER" ] && [ "$ENHANCED_SWAP_ROUTER" != "0x0000000000000000000000000000000000000000" ]; then
cast send "$ENHANCED_SWAP_ROUTER" "setDodoPoolAddress(address,address,address)" "$QUOTE_TOKEN" "$token_addr" "$pool_addr" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy -q 2>/dev/null && log_success "Router set QUOTE->token" || log_warn "Router set failed"
cast send "$ENHANCED_SWAP_ROUTER" "setDodoPoolAddress(address,address,address)" "$token_addr" "$QUOTE_TOKEN" "$pool_addr" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy -q 2>/dev/null && log_success "Router set token->QUOTE" || log_warn "Router set failed"
fi
if [ -n "$ASSET_REGISTRY" ] && [ "$ASSET_REGISTRY" != "0x0000000000000000000000000000000000000000" ]; then
cast send "$ASSET_REGISTRY" "updatePMMPool(address,address)" "$token_addr" "$pool_addr" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy -q 2>/dev/null && log_success "Registry updatePMMPool" || log_warn "Registry updatePMMPool failed"
fi
total_created=$((total_created + 1))
else
log_error "Failed to create pool for $token_addr"
fi
done
if [ "$count" -lt "$LIMIT" ]; then
break
fi
offset=$((offset + LIMIT))
done
log_info ""
log_info "Done. Pools created: $total_created, skipped (already had DODO): $total_skipped"

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Deploy ISO-4217W Token System (ISO-009 to ISO-018)
# Requires: PRIVATE_KEY, RPC_URL (ChainID 138)
# Optional: CUSTODIAN_ADDRESS, RESERVE_MANAGER_ADDRESS, RESERVE_TRANSMITTER_1, RESERVE_TRANSMITTER_2
set -euo pipefail
cd "$(dirname "$0")/.."
source .env 2>/dev/null || true
: "${PRIVATE_KEY:?PRIVATE_KEY required}"
: "${RPC_URL:?RPC_URL required (e.g. http://192.168.11.250:8545)}"
echo "Deploying ISO-4217W Token System..."
forge script script/deploy/iso4217w/DeployISO4217WSystem.s.sol:DeployISO4217WSystem \
--rpc-url "$RPC_URL" \
--broadcast \
--verify

18
scripts/deploy-vault-system.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
# Deploy Vault System (VLT-010 to VLT-018)
# Requires: PRIVATE_KEY, RPC_URL (ChainID 138)
# Optional: TREASURY_ADDRESS
set -euo pipefail
cd "$(dirname "$0")/.."
source .env 2>/dev/null || true
: "${PRIVATE_KEY:?PRIVATE_KEY required}"
: "${RPC_URL:?RPC_URL required (e.g. http://192.168.11.250:8545)}"
echo "Deploying Vault System..."
forge script script/deploy/vault/DeployVaultSystem.s.sol:DeployVaultSystem \
--rpc-url "$RPC_URL" \
--broadcast \
--verify

View File

@@ -0,0 +1,288 @@
#!/usr/bin/env bash
# Check deployer balances on all configured networks, estimate gas costs via gas API,
# ensure sufficient network token, then optionally deploy (Chain 138 phased core).
# Uses PRIVATE_KEY from .env (smom-dbis-138).
#
# Balance check: On EVM chains only the NATIVE token can be used for gas. We check that
# token for each network (cast balance = native currency). ERC-20 tokens (USDT, LINK, etc.)
# cannot be used for gas unless a meta-tx relayer is in use.
#
# Gas token per network (only these can be used for gas):
# Chain 138, Ethereum, Base, Optimism, Sepolia, Base Sepolia, Optimism Sepolia → ETH
# Polygon, Polygon Amoy → MATIC
# BSC → BNB
# Avalanche → AVAX
# Cronos → CRO
# Gnosis → xDAI
# Arbitrum → ETH
#
# Usage:
# ./scripts/deployment/check-balances-gas-and-deploy.sh # report only
# ./scripts/deployment/check-balances-gas-and-deploy.sh --deploy # deploy on Chain 138 (requires PRIVATE_KEY)
#
# Uses .env for RPCs and PRIVATE_KEY; --deploy is a tag (not .env).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
parse_deploy_tag "$@"
DO_DEPLOY="${DO_DEPLOY:-0}"
# Load .env (load_deployment_env already did; keep for any vars set after)
if [ -f .env ]; then
set -a
source .env
set +a
fi
# Infura: use Basic Auth URL when INFURA_PROJECT_SECRET is set (fixes "error sending request" from Infura)
SCRIPT_LIB="$SCRIPT_DIR/../lib"
[ -f "${SCRIPT_LIB}/infura.sh" ] && source "${SCRIPT_LIB}/infura.sh"
# Deployer address: use DEPLOYER_ADDRESS if set (matches MetaMask Portfolio), else derive from PRIVATE_KEY
if [ -n "${DEPLOYER_ADDRESS:-}" ]; then
DEPLOYER="${DEPLOYER_ADDRESS}"
[[ "$DEPLOYER" != 0x* ]] && DEPLOYER="0x$DEPLOYER"
else
if [ -z "${PRIVATE_KEY:-}" ]; then
echo "ERROR: Set PRIVATE_KEY in .env or set DEPLOYER_ADDRESS=0x4A666F96fC8764181194447A7dFdb7d471b301C8 for read-only balance check"
exit 1
fi
DEPLOYER=$(cast wallet address "$PRIVATE_KEY" 2>/dev/null || true)
if [ -z "$DEPLOYER" ]; then
echo "ERROR: Could not derive deployer address from PRIVATE_KEY (is 'cast' available?)"
exit 1
fi
fi
# Gas estimate for "full" deploy per chain (conservative)
GAS_FULL_DEPLOY_138="${GAS_FULL_DEPLOY_138:-5000000}"
GAS_FULL_DEPLOY_MAINNET="${GAS_FULL_DEPLOY_MAINNET:-5000000}"
BUFFER_BPS=120 # 20% buffer
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Short form for matching MetaMask Portfolio (0x4A66...b301C8)
DEPLOYER_SHORT="${DEPLOYER:0:6}...${DEPLOYER: -6}"
echo -e "${BLUE}============================================${NC}"
echo -e "${BLUE}Deployer balance & gas check (all networks)${NC}"
echo -e "${BLUE}============================================${NC}"
echo "Deployer: $DEPLOYER_SHORT (full: $DEPLOYER)"
echo " (Matches MetaMask Portfolio when RPCs are reachable; use DEPLOYER_ADDRESS=0x... to check a specific wallet)"
echo ""
# Format wei to ether with 8 decimal places (avoids excessive decimals from cast)
format_wei_to_ether() {
local wei="${1:-0}"
local eth
eth=$(echo "scale=10; $wei / 1000000000000000000" | bc 2>/dev/null) || eth="0"
printf "%.8f" "${eth:-0}"
}
# Infura Gas API: supported chain IDs (EIP-1559 style; API returns suggestedMaxFeePerGas in gwei)
INFURA_GAS_API_CHAINS="1 137 10 8453 42161 11155111 84532 11155420 80002 43114 56 100 324 534352"
# Get gas price in wei from Infura Gas API for a given chain_id (optional).
# Returns wei or empty; caller should fallback to cast gas-price.
get_gas_price_wei_infura_api() {
local chain_id="${1:-1}"
local key=""
if [ -n "${INFURA_GAS_API:-}" ]; then
local url="$INFURA_GAS_API"
if [[ "$url" == *"/v3/"* ]]; then
key="${url#*v3/}"
key="${key%%/*}"
else
key="$url"
fi
elif [ -n "${INFURA_PROJECT_ID:-}" ]; then
key="${INFURA_PROJECT_ID}"
fi
if [ -z "$key" ] || ! command -v curl >/dev/null 2>&1 || ! command -v jq >/dev/null 2>&1; then
return 1
fi
local api_url="https://gas.api.infura.io/v3/${key}/networks/${chain_id}/suggestedGasFees"
local res
res=$(curl -sL --connect-timeout 5 "$api_url" 2>/dev/null || true)
if [ -z "$res" ] || echo "$res" | grep -qi "error\|required\|private key\|not found"; then
return 1
fi
local gwei
gwei=$(echo "$res" | jq -r '.medium.suggestedMaxFeePerGas // .standard.suggestedMaxFeePerGas // .standard.maxFeePerGas // .low.suggestedMaxFeePerGas // empty' 2>/dev/null)
if [ -z "$gwei" ] || [ "$gwei" = "null" ]; then
return 1
fi
local wei
wei=$(echo "scale=0; ($gwei) * 1000000000 / 1" | bc 2>/dev/null)
[ -n "$wei" ] && [ "$wei" != "0" ] && echo "$wei"
}
# Get mainnet gas price from Infura Gas API (preferred) or RPC fallback.
get_mainnet_gas_price_wei() {
local wei
wei=$(get_gas_price_wei_infura_api 1)
if [ -z "$wei" ] || [ "$wei" = "0" ]; then
[ -n "${ETHEREUM_MAINNET_RPC:-}" ] && command -v cast >/dev/null 2>&1 && wei=$(cast gas-price --rpc-url "$ETHEREUM_MAINNET_RPC" 2>/dev/null || true)
fi
[ -n "$wei" ] && [ "$wei" != "0" ] && echo "$wei" || echo "30000000000"
}
# Resolve gas price for a chain: try Infura Gas API first (if chain supported), else RPC, else default_wei.
# Usage: get_gas_price_for_chain chain_id rpc_url default_wei
# Output: wei (and sets GAS_SOURCE="Infura Gas API" or "RPC" or "default")
get_gas_price_for_chain() {
local chain_id="$1"
local rpc_url="$2"
local default_wei="${3:-30000000000}"
local wei=""
[ -n "$rpc_url" ] && type ensure_infura_rpc_url &>/dev/null && rpc_url=$(ensure_infura_rpc_url "$rpc_url")
if [[ " $INFURA_GAS_API_CHAINS " == *" $chain_id "* ]]; then
wei=$(get_gas_price_wei_infura_api "$chain_id")
[ -n "$wei" ] && GAS_SOURCE="Infura Gas API" && echo "$wei" && return
fi
if [ -n "$rpc_url" ] && command -v cast >/dev/null 2>&1; then
wei=$(cast gas-price --rpc-url "$rpc_url" 2>/dev/null || true)
[ -n "$wei" ] && [ "$wei" != "0" ] && GAS_SOURCE="RPC" && echo "$wei" && return
fi
GAS_SOURCE="default"
echo "$default_wei"
}
mainnet_gas_wei=$(get_mainnet_gas_price_wei)
mainnet_gas_gwei=$(printf "%.2f" $(echo "scale=4; $mainnet_gas_wei / 1000000000" | bc 2>/dev/null || echo "30"))
echo "Gas prices (verified via Infura Gas API where supported, else RPC or default):"
echo " Ethereum Mainnet (1): ${mainnet_gas_gwei} gwei (Infura Gas API)"
echo ""
# Check native (gas) token balance for one network. Only this token can be used for gas on EVM.
check_network() {
local name="$1"
local rpc="$2"
local chain_id="${3:-}"
local gas_token="${4:-ETH}"
local gas_limit="${5:-$GAS_FULL_DEPLOY_MAINNET}"
local gas_price_wei="${6:-$mainnet_gas_wei}"
if [ -z "$rpc" ]; then
echo -e " ${YELLOW}$name (chain $chain_id): no RPC — gas token = $gas_token (not checked)${NC}"
return 0
fi
type ensure_infura_rpc_url &>/dev/null && rpc=$(ensure_infura_rpc_url "$rpc")
local balance_wei
balance_wei=$(cast balance "$DEPLOYER" --rpc-url "$rpc" 2>/dev/null) || balance_wei=""
local rpc_ok=1
if [ -z "$balance_wei" ] || ! [[ "$balance_wei" =~ ^[0-9]+$ ]]; then
rpc_ok=0
balance_wei="0"
fi
local balance_display
if [ "$rpc_ok" = "0" ]; then
balance_display="(unable to fetch — RPC unreachable?)"
else
balance_display=$(format_wei_to_ether "$balance_wei")
fi
local cost_wei
cost_wei=$(echo "$gas_limit * $gas_price_wei" | bc 2>/dev/null || echo "0")
local cost_with_buffer
cost_with_buffer=$(echo "$cost_wei * $BUFFER_BPS / 100" | bc 2>/dev/null || echo "$cost_wei")
local cost_display
cost_display=$(format_wei_to_ether "$cost_with_buffer")
local ok=0
[ "$rpc_ok" = "1" ] && [ "$(echo "$balance_wei >= $cost_with_buffer" | bc 2>/dev/null)" = "1" ] && ok=1
if [ "$ok" = "1" ]; then
echo -e " ${GREEN}$name (chain $chain_id): gas token $gas_token — balance ${balance_display}, required ~${cost_display} — OK for deploy${NC}"
elif [ "$rpc_ok" = "0" ]; then
echo -e " ${YELLOW}$name (chain $chain_id): gas token $gas_token — balance ${balance_display}, required ~${cost_display} — check RPC / run from network with access${NC}"
else
echo -e " ${RED}$name (chain $chain_id): gas token $gas_token — balance ${balance_display}, required ~${cost_display} — INSUFFICIENT for deploy${NC}"
fi
return $((1 - ok))
}
# All networks: order matches MetaMask Portfolio (Ethereum, BSC, Arbitrum, Optimism, Polygon, Cronos, …)
# Gas needed from Infura Gas API or RPC. Native gas token only (ETH, BNB, POL, CRO, etc.).
echo "Checking gas token balance (same order as MetaMask Portfolio where applicable):"
echo ""
any_insufficient=0
# --- Portfolio main networks (Ethereum, BSC, Arbitrum, Optimism, Polygon, Cronos) ---
check_network "Ethereum Mainnet" "${ETHEREUM_MAINNET_RPC:-}" "1" "ETH" "$GAS_FULL_DEPLOY_MAINNET" "$mainnet_gas_wei" || any_insufficient=1
check_network "BSC" "${BSC_RPC_URL:-${BSC_MAINNET_RPC:-https://bsc-dataseed.binance.org}}" "56" "BNB" "5000000" "$(get_gas_price_for_chain 56 "${BSC_RPC_URL:-${BSC_MAINNET_RPC:-}}" "5000000000")" || true
check_network "Arbitrum" "${ARBITRUM_MAINNET_RPC:-https://arbitrum-one.publicnode.com}" "42161" "ETH" "5000000" "$(get_gas_price_for_chain 42161 "${ARBITRUM_MAINNET_RPC:-}" "100000000")" || true
check_network "Optimism" "${OPTIMISM_MAINNET_RPC:-}" "10" "ETH" "5000000" "$(get_gas_price_for_chain 10 "${OPTIMISM_MAINNET_RPC:-}" "1000000")" || true
check_network "Polygon" "${POLYGON_MAINNET_RPC:-}" "137" "POL" "5000000" "$(get_gas_price_for_chain 137 "${POLYGON_MAINNET_RPC:-}" "50000000000")" || any_insufficient=1
check_network "Cronos" "${CRONOS_RPC_URL:-https://evm.cronos.org}" "25" "CRO" "5000000" "$(get_gas_price_for_chain 25 "${CRONOS_RPC_URL:-}" "1000000000")" || true
# --- Chain 138 (project chain) ---
check_network "Chain 138" "${RPC_URL_138:-}" "138" "ETH" "$GAS_FULL_DEPLOY_138" "$(cast gas-price --rpc-url "${RPC_URL_138:-http://192.168.11.211:8545}" 2>/dev/null || echo "1000000000")" || any_insufficient=1
# --- Other mainnets ---
check_network "Base" "${BASE_MAINNET_RPC:-}" "8453" "ETH" "5000000" "$(get_gas_price_for_chain 8453 "${BASE_MAINNET_RPC:-}" "100000000")" || true
check_network "Avalanche" "${AVALANCHE_RPC_URL:-${AVALANCHE_MAINNET_RPC:-https://avalanche-c-chain.publicnode.com}}" "43114" "AVAX" "5000000" "$(get_gas_price_for_chain 43114 "${AVALANCHE_RPC_URL:-${AVALANCHE_MAINNET_RPC:-}}" "25000000000")" || true
check_network "Gnosis" "${GNOSIS_MAINNET_RPC:-${GNOSIS_RPC:-https://rpc.gnosischain.com}}" "100" "xDAI" "5000000" "$(get_gas_price_for_chain 100 "${GNOSIS_MAINNET_RPC:-${GNOSIS_RPC:-}}" "1000000000")" || true
# --- Testnets ---
check_network "Ethereum Sepolia" "${ETHEREUM_SEPOLIA_RPC:-}" "11155111" "ETH" "5000000" "$(get_gas_price_for_chain 11155111 "${ETHEREUM_SEPOLIA_RPC:-}" "20000000000")" || true
check_network "Polygon Amoy" "${POLYGON_AMOY_RPC:-}" "80002" "MATIC" "5000000" "$(get_gas_price_for_chain 80002 "${POLYGON_AMOY_RPC:-}" "30000000000")" || true
check_network "Base Sepolia" "${BASE_SEPOLIA_RPC:-}" "84532" "ETH" "5000000" "$(get_gas_price_for_chain 84532 "${BASE_SEPOLIA_RPC:-}" "100000000")" || true
check_network "Optimism Sepolia" "${OPTIMISM_SEPOLIA_RPC:-}" "11155420" "ETH" "5000000" "$(get_gas_price_for_chain 11155420 "${OPTIMISM_SEPOLIA_RPC:-}" "1000000")" || true
echo ""
echo "Gas token summary: each chain uses only its native token for gas. ERC-20 (USDT, LINK, etc.) cannot pay gas."
echo "Gas needed above was computed from: Infura Gas API (chains 1, 10, 56, 100, 137, 42161, 43114, 8453, 84532, 80002, 11155111, 11155420) or RPC eth_gasPrice when API unavailable."
echo ""
if [ "${DO_DEPLOY:-0}" = "1" ]; then
if [ -n "${DEPLOYER_ADDRESS:-}" ]; then
echo -e "${RED}ERROR: --deploy requires PRIVATE_KEY in .env (unset DEPLOYER_ADDRESS to use key-derived deployer).${NC}"
exit 1
fi
if [ -z "${PRIVATE_KEY:-}" ]; then
echo -e "${RED}ERROR: PRIVATE_KEY required for --deploy.${NC}"
exit 1
fi
echo -e "${BLUE}Deploy phase (Chain 138 only; other chains need CCIP_* env)${NC}"
RPC_138="${RPC_URL_138:-http://192.168.11.211:8545}"
balance_138=$(cast balance "$DEPLOYER" --rpc-url "$RPC_138" 2>/dev/null || echo "0")
need_138=$(echo "5000000 * 1000000000 * $BUFFER_BPS / 100" | bc 2>/dev/null || echo "6000000000000000000")
if [ -n "$balance_138" ] && [ "$(echo "$balance_138 >= $need_138" | bc 2>/dev/null)" = "1" ]; then
echo "Deploying phased core (01_DeployCore, 02_DeployBridges) on Chain 138..."
export PRIVATE_KEY
out_01=$(mktemp)
trap "rm -f $out_01" EXIT
# Chain 138 often requires minimum gas price (e.g. 1 gwei)
GAS_PRICE_138="${GAS_PRICE_138:-1000000000}"
if forge script script/deploy/01_DeployCore.s.sol:DeployCore \
--rpc-url "$RPC_138" \
--private-key "$PRIVATE_KEY" \
--broadcast \
--with-gas-price "$GAS_PRICE_138" \
-vvv 2>&1 | tee "$out_01"; then
reg=$(grep "UNIVERSAL_ASSET_REGISTRY" "$out_01" | tail -1 | grep -oE "0x[a-fA-F0-9]{40}" | head -1)
if [ -n "$reg" ] && [ -n "${CCIP_ROUTER:-}" ]; then
export UNIVERSAL_ASSET_REGISTRY="$reg"
forge script script/deploy/02_DeployBridges.s.sol:DeployBridges \
--rpc-url "$RPC_138" \
--private-key "$PRIVATE_KEY" \
--broadcast \
--with-gas-price "$GAS_PRICE_138" \
-vvv 2>&1 || echo "02_DeployBridges failed or skipped."
fi
else
echo "01_DeployCore failed or skipped (may already be deployed)."
fi
echo -e "${GREEN}Chain 138 deploy phase finished.${NC}"
else
echo -e "${RED}Chain 138 balance insufficient for deploy (need more native ETH on 138). Fund deployer and re-run.${NC}"
exit 1
fi
else
echo "Run with --deploy to run deployment on Chain 138 (phased core)."
echo "Other chains: fund deployer with that chain's native token (MATIC, BNB, etc.) and set CCIP_* in .env for DeployAll."
fi

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env bash
# Confirm Cronos deployments: test CRONOSCAN_API_KEY, verify contracts on-chain.
# See docs/04-configuration/CRONOS_EXPLORER_OPERATIONS.md
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source .env 2>/dev/null || true
RPC="${CRONOS_RPC_URL:-https://evm.cronos.org}"
CONTRACTS=(
"0x99B3511A2d315A497C8112C1fdd8D508d4B1E506:WETH9"
"0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6:WETH10"
"0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e:CCIPWETH9Bridge"
"0x105F8A15b819948a89153505762444Ee9f324684:CCIPWETH10Bridge"
)
echo "=== Cronos (Chain 25) deployment confirmation ==="
echo ""
# 1. On-chain confirmation via RPC (eth_getCode)
echo "1. On-chain bytecode check (RPC: $RPC):"
ok=0 missing=0
for entry in "${CONTRACTS[@]}"; do
addr="${entry%%:*}"
name="${entry##*:}"
code=$(cast code "$addr" --rpc-url "$RPC" 2>/dev/null || echo "0x")
if [ "${#code}" -gt 10 ]; then
echo "$name ($addr)"
((ok++)) || true
else
echo "$name ($addr) — no bytecode"
((missing++)) || true
fi
done
echo " Summary: $ok confirmed, $missing missing"
echo ""
# 2. Explorer API (if key set)
if [ -n "${CRONOSCAN_API_KEY:-}" ]; then
echo "2. Cronos Explorer API (CRONOSCAN_API_KEY):"
BLOCK=$(curl -s "https://explorer-api.cronos.org/mainnet/api/v1/ethproxy/getBlockNumber?apikey=${CRONOSCAN_API_KEY}")
if echo "$BLOCK" | grep -q '"result"'; then
NUM=$(echo "$BLOCK" | jq -r '.result')
echo " ✓ Block number: $NUM (dec: $((NUM)))"
else
echo " ✗ API error: $BLOCK"
fi
echo ""
else
echo "2. Cronos Explorer API: SKIP (set CRONOSCAN_API_KEY for block/explorer data)"
echo ""
fi
# 3. Verification instructions
echo "3. Contract verification:"
echo " Manual: https://explorer.cronos.org/verifyContract"
echo " Per-address: https://explorer.cronos.org/address/<ADDR>"
echo ""
echo "Full reference: docs/04-configuration/CRONOS_EXPLORER_OPERATIONS.md"

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Check Cronos contract deployment and verification status.
# Verification status must be checked manually by visiting each explorer URL;
# this script confirms on-chain deployment and prints links.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
RPC="${CRONOS_RPC_URL:-https://evm.cronos.org}"
CONTRACTS=(
"0x99B3511A2d315A497C8112C1fdd8D508d4B1E506:WETH9"
"0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6:WETH10"
"0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e:CCIPWETH9Bridge"
"0x105F8A15b819948a89153505762444Ee9f324684:CCIPWETH10Bridge"
)
echo "=== Cronos (Chain 25) contract status ==="
echo ""
echo "On-chain deployment:"
for entry in "${CONTRACTS[@]}"; do
addr="${entry%%:*}"
name="${entry##*:}"
code=$(cast code "$addr" --rpc-url "$RPC" 2>/dev/null || echo "0x")
if [ "${#code}" -gt 10 ]; then
echo "$name — DEPLOYED"
else
echo "$name — MISSING"
fi
done
echo ""
echo "Verification status (check each link manually):"
echo " Verified contracts show 'Contract Source Code Verified' or display source."
echo ""
for entry in "${CONTRACTS[@]}"; do
addr="${entry%%:*}"
name="${entry##*:}"
echo " $name: https://explorer.cronos.org/address/$addr"
done
echo ""
echo "Run ./scripts/deployment/export-cronos-verification-sources.sh and follow"
echo "docs/deployment/CRONOS_VERIFICATION_RUNBOOK.md to verify unverified contracts."

View File

@@ -0,0 +1,59 @@
#!/usr/bin/env bash
# Check that .env has the VITE_* (and related) vars needed for frontend-dapp production build.
# Usage: ./scripts/deployment/check-dapp-env.sh [path-to-.env]
# Exit 0 if all required are set; exit 1 and list missing if not.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
ENV_FILE="${1:-$REPO_ROOT/.env}"
get_var() {
local name="$1"
if [[ ! -f "$ENV_FILE" ]]; then
echo ""
return
fi
local line
line="$(grep -E "^(export[[:space:]]+)?${name}=" "$ENV_FILE" 2>/dev/null | head -1)"
if [[ -n "$line" ]]; then
echo "$line" | sed -E 's/^(export[[:space:]]+)?[^=]+=//' | sed 's/^["'\'' ]//;s/["'\'' ]$//' | xargs
else
echo ""
fi
}
REQUIRED_FOR_BUILD=(
"VITE_RPC_URL_138"
)
OPTIONAL_BUT_RECOMMENDED=(
"VITE_LOCKBOX_138"
"VITE_INBOX_ETH_MAINNET"
"VITE_LIQUIDITY_POOL_ETH_MAINNET"
"VITE_DUAL_ROUTER_BRIDGE_SWAP_COORDINATOR"
"VITE_CHALLENGE_MANAGER_MAINNET"
"VITE_WALLETCONNECT_PROJECT_ID"
"VITE_THIRDWEB_CLIENT_ID"
)
missing=()
for v in "${REQUIRED_FOR_BUILD[@]}"; do
val="$(get_var "$v")"
if [[ -z "$val" || "$val" == "0x..." || "$val" == "your-"* ]]; then
missing+=("$v")
fi
done
if [[ ${#missing[@]} -gt 0 ]]; then
echo "Missing or placeholder required for DApp build: ${missing[*]}"
echo "Set them in $ENV_FILE (or copy from .env.example and fill)."
exit 1
fi
echo "Required VITE_* for DApp build are set."
for v in "${OPTIONAL_BUT_RECOMMENDED[@]}"; do
val="$(get_var "$v")"
if [[ -z "$val" || "$val" == "0x..." || "$val" == "your-"* ]]; then
echo "Optional (recommended): $v"
fi
done
exit 0

View File

@@ -0,0 +1,65 @@
#!/usr/bin/env bash
# Check smom-dbis-138/.env for required and optional variable names (no values printed).
# Usage: ./scripts/deployment/check-env-required.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
ENV_FILE="${PROJECT_ROOT}/.env"
echo "=== .env check (keys only, no values) ==="
echo ""
if [ ! -f "$ENV_FILE" ]; then
echo " .env: MISSING"
exit 1
fi
# Build list of key names (strip values; never print values)
keys_file=$(mktemp)
trap 'rm -f "$keys_file"' EXIT
grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$ENV_FILE" 2>/dev/null | sed 's/=.*//' > "$keys_file" || true
grep -E '^export [A-Za-z_][A-Za-z0-9_]*=' "$ENV_FILE" 2>/dev/null | sed 's/^export //; s/=.*//' >> "$keys_file" || true
sort -u "$keys_file" -o "$keys_file"
check() { grep -qx "$1" "$keys_file" 2>/dev/null; }
total=$(wc -l < "$keys_file")
echo " .env: EXISTS ($total keys)"
echo ""
# Required for deploy-contracts-unified.sh and most Chain 138 scripts
echo "--- Required (deploy / Chain 138) ---"
for k in PRIVATE_KEY RPC_URL RPC_URL_138; do
check "$k" && echo " OK $k" || echo " MISS $k"
done
# PRIVATE_KEY format: 64 hex chars (no value printed)
if check "PRIVATE_KEY"; then
len=$(awk -F= '/^PRIVATE_KEY=/ { v=$2; gsub(/^0x/,"",v); print length(v) }' "$ENV_FILE" 2>/dev/null || echo "0")
[ "$len" = "64" ] && echo " PRIVATE_KEY format: 64-char hex" || echo " PRIVATE_KEY format: WARN (length=$len, expected 64)"
fi
echo ""
# Optional for PMM pool script (create-all-dodo-pools-from-token-api.sh)
echo "--- Optional (PMM pools: DODO_PMM_INTEGRATION or DODO_PMM_INTEGRATION_ADDRESS, QUOTE_TOKEN or QUOTE_TOKEN_ADDRESS / WETH_ADDRESS_138) ---"
for k in DODO_PMM_INTEGRATION DODO_PMM_INTEGRATION_ADDRESS QUOTE_TOKEN QUOTE_TOKEN_ADDRESS WETH_ADDRESS_138; do
check "$k" && echo " OK $k" || echo " -- $k"
done
echo ""
# Optional for mainnet dry-run
echo "--- Optional (mainnet dry-run) ---"
for k in ETHEREUM_MAINNET_RPC; do
check "$k" && echo " OK $k" || echo " -- $k"
done
echo ""
# Common CCIP / bridge
echo "--- Optional (CCIP / bridge) ---"
for k in CCIP_ROUTER LINK_TOKEN CCIPWETH9_BRIDGE_CHAIN138 CCIPWETH10_BRIDGE_CHAIN138; do
check "$k" && echo " OK $k" || echo " -- $k"
done
echo ""
echo "Done. Fix any MISS above; -- means optional and can be set when needed."

View File

@@ -0,0 +1,86 @@
#!/usr/bin/env bash
# Check deployer LINK balance on Gnosis, Cronos, Celo (config-ready chains).
# Required before fund-ccip-bridges-with-link.sh: 20 LINK per chain (10 per bridge).
#
# Usage: ./scripts/deployment/check-link-balance-config-ready-chains.sh [gnosis|cronos|celo|all]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
[[ -f "$PROJECT_ROOT/.env" ]] && set -a && source "$PROJECT_ROOT/.env" && set +a
CHAIN="${1:-all}"
REQUIRED_LINK="20" # 10 per WETH9 bridge + 10 per WETH10 bridge
# LINK token addresses (from CCIP directory)
LINK_TOKEN_GNOSIS="${LINK_TOKEN_GNOSIS:-${CCIP_GNOSIS_LINK_TOKEN:-0xE2e73A1c69ecF83F464EFCE6A5be353a37cA09b2}}"
LINK_TOKEN_CRONOS="${LINK_TOKEN_CRONOS:-${CCIP_CRONOS_LINK_TOKEN:-0x8c80A01F461f297Df7F9DA3A4f740D7297C8Ac85}}"
LINK_TOKEN_CELO="${LINK_TOKEN_CELO:-${CCIP_CELO_LINK_TOKEN:-0xd07294e6E917e07dfDcee882dd1e2565085C2ae0}}"
GNOSIS_RPC="${GNOSIS_RPC:-https://rpc.gnosischain.com}"
CRONOS_RPC="${CRONOS_RPC:-https://evm.cronos.org}"
CELO_RPC="${CELO_RPC:-https://forno.celo.org}"
if [[ -z "${PRIVATE_KEY:-}" ]]; then
echo "Error: Set PRIVATE_KEY in .env" >&2
exit 1
fi
DEPLOYER=$(cast wallet address "$PRIVATE_KEY" 2>/dev/null || true)
[[ -z "$DEPLOYER" ]] && { echo "Error: Could not derive deployer from PRIVATE_KEY" >&2; exit 1; }
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
check_link() {
local name="$1" rpc="$2" link_token="$3"
[[ -z "$rpc" || -z "$link_token" ]] && return 1
local raw
raw=$(cast call "$link_token" "balanceOf(address)(uint256)" "$DEPLOYER" --rpc-url "$rpc" 2>/dev/null || echo "0")
local link_val
link_val=$(echo "scale=4; $raw / 1000000000000000000" | bc 2>/dev/null || echo "0")
if [[ -z "$link_val" || "$link_val" == "0" ]]; then
echo -e " ${RED}${NC} $name: 0 LINK (need $REQUIRED_LINK LINK)"
return 1
fi
if [[ "$(echo "$link_val >= $REQUIRED_LINK" | bc 2>/dev/null)" == "1" ]]; then
echo -e " ${GREEN}${NC} $name: $link_val LINK"
return 0
fi
echo -e " ${YELLOW}${NC} $name: $link_val LINK (need $REQUIRED_LINK LINK)"
return 1
}
echo "=== LINK Balance Check (Config-Ready Chains) ==="
echo "Deployer: ${DEPLOYER:0:10}...${DEPLOYER: -8}"
echo "Required: $REQUIRED_LINK LINK per chain (10 per WETH9 + 10 per WETH10 bridge)"
echo ""
failed=0
case "$CHAIN" in
gnosis) check_link "Gnosis" "$GNOSIS_RPC" "$LINK_TOKEN_GNOSIS" || failed=1 ;;
cronos) check_link "Cronos" "$CRONOS_RPC" "$LINK_TOKEN_CRONOS" || failed=1 ;;
celo) check_link "Celo" "$CELO_RPC" "$LINK_TOKEN_CELO" || failed=1 ;;
all)
check_link "Gnosis" "$GNOSIS_RPC" "$LINK_TOKEN_GNOSIS" || failed=1
check_link "Cronos" "$CRONOS_RPC" "$LINK_TOKEN_CRONOS" || failed=1
check_link "Celo" "$CELO_RPC" "$LINK_TOKEN_CELO" || failed=1
;;
*) echo "Usage: $0 [gnosis|cronos|celo|all]"; exit 1 ;;
esac
echo ""
if [[ $failed -eq 0 ]]; then
echo "LINK balance OK. Run: ./scripts/deployment/fund-ccip-bridges-with-link.sh"
exit 0
else
echo "Acquire LINK on each chain (bridge from mainnet or DEX), then re-run this check."
echo " Gnosis: $LINK_TOKEN_GNOSIS"
echo " Cronos: $LINK_TOKEN_CRONOS"
echo " Celo: $LINK_TOKEN_CELO"
exit 1
fi

View File

@@ -0,0 +1,38 @@
#!/usr/bin/env bash
# Check bash syntax of deployment scripts and lib (bash -n). Run from anywhere.
# Usage: ./scripts/deployment/check-syntax.sh or bash scripts/deployment/check-syntax.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
FAIL=0
check() {
if bash -n "$1" 2>/dev/null; then
echo " OK $1"
else
echo " FAIL $1"
FAIL=1
fi
}
echo "Checking deployment scripts and lib..."
check scripts/lib/deployment/prompts.sh
check scripts/lib/deployment/dotenv.sh
check scripts/deployment/fund-mainnet-lp.sh
check scripts/deployment/run-all-four-gaps.sh
check scripts/deployment/deploy-pmm-all-l2s.sh
check scripts/deployment/deploy-trustless-l2s.sh
check scripts/deployment/fund-ccip-bridges-with-link.sh
check scripts/deployment/fix-nonce-and-retry.sh
check scripts/deployment/run-remaining-g2g3-with-nonce-fix.sh
check scripts/deployment/run-pmm-and-pools.sh
check scripts/deployment/check-balances-gas-and-deploy.sh
if [[ "$FAIL" -eq 0 ]]; then
echo "All passed."
else
echo "Some checks failed."
exit 1
fi

View File

@@ -0,0 +1,136 @@
#!/usr/bin/env bash
# Complete CCIP bridge configuration for Config-Ready chains (Gnosis, Celo, Wemix).
# - Adds each chain as destination on Chain 138 bridges (138 → Gnosis/Celo/Wemix).
# - Adds Chain 138 as destination on each chain's bridges (Gnosis/Celo/Wemix → 138).
# Requires: bridge addresses and RPCs in .env; PRIVATE_KEY; CHAIN138_SELECTOR for step 2.
# Usage: ./scripts/deployment/complete-config-ready-chains.sh
# DRY_RUN=1 ./scripts/deployment/complete-config-ready-chains.sh # print commands only
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
[[ -f "$SCRIPT_DIR/../lib/init.sh" ]] && source "$SCRIPT_DIR/../lib/init.sh" 2>/dev/null || true
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
if [[ -f "$PROJECT_ROOT/.env" ]]; then
set -a
source "$PROJECT_ROOT/.env"
set +a
fi
# Chain selectors (decimal, for addDestination(uint64,address))
ETH_MAINNET_SELECTOR="${ETH_MAINNET_SELECTOR:-5009297550715157269}"
GNOSIS_SELECTOR="${GNOSIS_SELECTOR:-465200170687744372}"
CRONOS_SELECTOR="${CRONOS_SELECTOR:-1456215246176062136}"
CELO_SELECTOR="${CELO_SELECTOR:-1346049177634351622}"
WEMIX_SELECTOR="${WEMIX_SELECTOR:-5142893604156789321}"
CHAIN138_SELECTOR="${CHAIN138_SELECTOR:-}"
CHAIN138_RPC="${CHAIN138_RPC:-${RPC_URL:-https://rpc-core.d-bis.org}}"
GNOSIS_RPC="${GNOSIS_RPC:-https://rpc.gnosischain.com}"
CRONOS_RPC="${CRONOS_RPC:-https://evm.cronos.org}"
CELO_RPC="${CELO_RPC:-https://forno.celo.org}"
WEMIX_RPC="${WEMIX_RPC:-https://api.wemix.com}"
PRIVATE_KEY="${PRIVATE_KEY:-}"
if [[ -n "$PRIVATE_KEY" && ! "$PRIVATE_KEY" =~ ^0x ]]; then
PRIVATE_KEY="0x$PRIVATE_KEY"
fi
# Chain 138 bridge addresses (required)
WETH9_138=$(grep "CCIPWETH9_BRIDGE_CHAIN138=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH9_BRIDGE_CHAIN138:-}")
WETH10_138=$(grep "CCIPWETH10_BRIDGE_CHAIN138=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH10_BRIDGE_CHAIN138:-}")
# Config-ready chain bridge addresses (optional; if set, we configure them)
WETH9_GNOSIS=$(grep "CCIPWETH9_BRIDGE_GNOSIS=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH9_BRIDGE_GNOSIS:-}")
WETH10_GNOSIS=$(grep "CCIPWETH10_BRIDGE_GNOSIS=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH10_BRIDGE_GNOSIS:-}")
WETH9_CRONOS=$(grep "CCIPWETH9_BRIDGE_CRONOS=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH9_BRIDGE_CRONOS:-}")
WETH10_CRONOS=$(grep "CCIPWETH10_BRIDGE_CRONOS=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH10_BRIDGE_CRONOS:-}")
WETH9_CELO=$(grep "CCIPWETH9_BRIDGE_CELO=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH9_BRIDGE_CELO:-}")
WETH10_CELO=$(grep "CCIPWETH10_BRIDGE_CELO=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH10_BRIDGE_CELO:-}")
WETH9_WEMIX=$(grep "CCIPWETH9_BRIDGE_WEMIX=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH9_BRIDGE_WEMIX:-}")
WETH10_WEMIX=$(grep "CCIPWETH10_BRIDGE_WEMIX=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "${CCIPWETH10_BRIDGE_WEMIX:-}")
DRY_RUN="${DRY_RUN:-0}"
log_info "=== Config-Ready Chains Completion (Gnosis, Cronos, Celo, Wemix) ==="
if [[ -z "$WETH9_138" || -z "$WETH10_138" ]]; then
echo "Error: Chain 138 bridge addresses not set. Set in .env: CCIPWETH9_BRIDGE_CHAIN138, CCIPWETH10_BRIDGE_CHAIN138" >&2
exit 1
fi
if [[ -z "$PRIVATE_KEY" ]]; then
echo "Error: PRIVATE_KEY not set in .env" >&2
exit 1
fi
run_or_echo() {
if [[ "$DRY_RUN" = "1" ]]; then
echo " [DRY RUN] $*"
else
if eval "$*" >/dev/null 2>&1; then
log_success " OK"
else
log_warn " Failed (non-fatal) - run manually to see error"
fi
fi
}
# ---- Step A: On Chain 138, add Gnosis/Cronos/Celo/Wemix as destinations ----
echo ""
echo "Step A: Chain 138 bridges → add Gnosis, Cronos, Celo, Wemix as destinations"
while IFS= read -r line; do
read -r label selector addr9 addr10 rpc <<< "$line"
if [[ -z "$addr9" && -z "$addr10" ]]; then
echo " Skip $label (no bridge addresses in .env)"
continue
fi
echo " Configuring Chain 138 → $label..."
if [[ -n "$addr9" ]]; then
run_or_echo "cast send $WETH9_138 \"addDestination(uint64,address)\" $selector $addr9 --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy --gas-limit 200000"
fi
if [[ -n "$addr10" ]]; then
run_or_echo "cast send $WETH10_138 \"addDestination(uint64,address)\" $selector $addr10 --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy --gas-limit 200000"
fi
done << EOF
Gnosis $GNOSIS_SELECTOR $WETH9_GNOSIS $WETH10_GNOSIS $GNOSIS_RPC
Cronos $CRONOS_SELECTOR $WETH9_CRONOS $WETH10_CRONOS $CRONOS_RPC
Celo $CELO_SELECTOR $WETH9_CELO $WETH10_CELO $CELO_RPC
Wemix $WEMIX_SELECTOR $WETH9_WEMIX $WETH10_WEMIX $WEMIX_RPC
EOF
# ---- Step B: On Gnosis/Cronos/Celo/Wemix, add Chain 138 as destination ----
if [[ -z "$CHAIN138_SELECTOR" ]]; then
echo ""
echo "Step B: Skipped (CHAIN138_SELECTOR not set in .env). Set it to configure remote chains → Chain 138."
echo " Example: CHAIN138_SELECTOR=<decimal from CCIP Router getChainSelector()>"
else
echo ""
echo "Step B: Gnosis/Cronos/Celo/Wemix bridges → add Chain 138 as destination"
while IFS= read -r line; do
read -r label rpc addr9 addr10 <<< "$line"
if [[ -z "$addr9" && -z "$addr10" ]]; then
echo " Skip $label (no bridge addresses)"
continue
fi
echo " Configuring $label → Chain 138..."
if [[ -n "$addr9" ]]; then
run_or_echo "cast send $addr9 \"addDestination(uint64,address)\" $CHAIN138_SELECTOR $WETH9_138 --rpc-url $rpc --private-key \$PRIVATE_KEY --legacy"
fi
if [[ -n "$addr10" ]]; then
run_or_echo "cast send $addr10 \"addDestination(uint64,address)\" $CHAIN138_SELECTOR $WETH10_138 --rpc-url $rpc --private-key \$PRIVATE_KEY --legacy"
fi
done << EOF
Gnosis $GNOSIS_RPC $WETH9_GNOSIS $WETH10_GNOSIS
Cronos $CRONOS_RPC $WETH9_CRONOS $WETH10_CRONOS
Celo $CELO_RPC $WETH9_CELO $WETH10_CELO
Wemix $WEMIX_RPC $WETH9_WEMIX $WETH10_WEMIX
EOF
fi
echo ""
log_success "Config-ready chains script finished."
echo " Next: Fund each remote bridge with LINK (see docs/07-ccip/CONFIG_READY_CHAINS_COMPLETION_RUNBOOK.md)."

View File

@@ -0,0 +1,130 @@
#!/usr/bin/env bash
# Configure CCIP bridge destinations for Avalanche, Arbitrum, Cronos ↔ Chain 138.
# Step A: On Chain 138, add Avalanche/Arbitrum/Cronos as destinations
# Step B: On Avalanche/Arbitrum/Cronos, add Chain 138 as destination
# Requires: bridge addresses and CHAIN138_SELECTOR in .env; PRIVATE_KEY; Chain 138 RPC reachable for Step A.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
if [[ -f .env ]]; then
set -a
source .env
set +a
fi
[[ -f "$SCRIPT_DIR/../lib/infura.sh" ]] && source "$SCRIPT_DIR/../lib/infura.sh"
# Chain selectors (decimal)
AVALANCHE_SELECTOR="${AVALANCHE_SELECTOR:-6433500567565415381}"
ARBITRUM_SELECTOR="${ARBITRUM_SELECTOR:-4949039107694359620}"
CRONOS_SELECTOR="${CRONOS_SELECTOR:-1456215246176062136}"
CHAIN138_SELECTOR="${CHAIN138_SELECTOR:-138}"
CHAIN138_RPC="${RPC_URL_138:-${CHAIN138_RPC:-http://192.168.11.211:8545}}"
# Prefer explicit RPC; else Infura (INFURA_PROJECT_ID + optional INFURA_PROJECT_SECRET); else public
_avalanche_infura=$(build_infura_rpc "avalanche-mainnet" 2>/dev/null || true)
_arbitrum_infura=$(build_infura_rpc "arbitrum-mainnet" 2>/dev/null || true)
AVALANCHE_RPC="${AVALANCHE_RPC_URL:-${AVALANCHE_RPC:-${_avalanche_infura:-https://avalanche-c-chain.publicnode.com}}}"
ARBITRUM_RPC="${ARBITRUM_MAINNET_RPC:-${ARBITRUM_RPC:-${_arbitrum_infura:-https://arbitrum-one.publicnode.com}}}"
CRONOS_RPC="${CRONOS_RPC_URL:-${CRONOS_RPC:-https://evm.cronos.org}}"
WETH9_138="${CCIPWETH9_BRIDGE_CHAIN138:-}"
WETH10_138="${CCIPWETH10_BRIDGE_CHAIN138:-}"
WETH9_AVALANCHE="${CCIPWETH9_BRIDGE_AVALANCHE:-}"
WETH10_AVALANCHE="${CCIPWETH10_BRIDGE_AVALANCHE:-}"
WETH9_ARBITRUM="${CCIPWETH9_BRIDGE_ARBITRUM:-}"
WETH10_ARBITRUM="${CCIPWETH10_BRIDGE_ARBITRUM:-}"
WETH9_CRONOS="${CCIPWETH9_BRIDGE_CRONOS:-}"
WETH10_CRONOS="${CCIPWETH10_BRIDGE_CRONOS:-}"
PRIVATE_KEY="${PRIVATE_KEY:-}"
[[ -n "$PRIVATE_KEY" && ! "$PRIVATE_KEY" =~ ^0x ]] && PRIVATE_KEY="0x$PRIVATE_KEY"
DRY_RUN="${DRY_RUN:-0}"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
run_or_echo() {
if [[ "$DRY_RUN" = "1" ]]; then
echo " [DRY RUN] $*"
else
if eval "$*"; then
echo -e " ${GREEN}OK${NC}"
else
echo -e " ${RED}Failed${NC}"
return 1
fi
fi
}
echo -e "${GREEN}=== Avalanche/Arbitrum/Cronos ↔ Chain 138 Bridge Configuration ===${NC}"
echo ""
if [[ -z "$PRIVATE_KEY" ]]; then
echo -e "${RED}ERROR: PRIVATE_KEY not set${NC}"
exit 1
fi
if [[ -z "$WETH9_138" ]]; then
echo -e "${RED}ERROR: CCIPWETH9_BRIDGE_CHAIN138 must be set in .env${NC}"
exit 1
fi
if [[ -z "$WETH10_138" ]]; then
echo -e "${YELLOW}NOTE: CCIPWETH10_BRIDGE_CHAIN138 not set; skipping WETH10 bridge configuration${NC}"
fi
echo "Step A: Chain 138 → add Avalanche, Arbitrum, Cronos as destinations"
echo " (Requires Chain 138 RPC reachable: $CHAIN138_RPC)"
echo ""
# Step A: Chain 138 → Avalanche
if [[ -n "$WETH9_AVALANCHE" || -n "$WETH10_AVALANCHE" ]]; then
echo " Chain 138 → Avalanche:"
[[ -n "$WETH9_AVALANCHE" ]] && run_or_echo "cast send $WETH9_138 'addDestination(uint64,address)' $AVALANCHE_SELECTOR $WETH9_AVALANCHE --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy" || true
[[ -n "$WETH10_AVALANCHE" ]] && run_or_echo "cast send $WETH10_138 'addDestination(uint64,address)' $AVALANCHE_SELECTOR $WETH10_AVALANCHE --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy" || true
fi
# Step A: Chain 138 → Arbitrum
if [[ -n "$WETH9_ARBITRUM" || -n "$WETH10_ARBITRUM" ]]; then
echo " Chain 138 → Arbitrum:"
[[ -n "$WETH9_ARBITRUM" ]] && run_or_echo "cast send $WETH9_138 'addDestination(uint64,address)' $ARBITRUM_SELECTOR $WETH9_ARBITRUM --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy" || true
[[ -n "$WETH10_ARBITRUM" ]] && run_or_echo "cast send $WETH10_138 'addDestination(uint64,address)' $ARBITRUM_SELECTOR $WETH10_ARBITRUM --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy" || true
fi
# Step A: Chain 138 → Cronos
if [[ -n "$WETH9_CRONOS" || -n "$WETH10_CRONOS" ]]; then
echo " Chain 138 → Cronos:"
[[ -n "$WETH9_CRONOS" ]] && run_or_echo "cast send $WETH9_138 'addDestination(uint64,address)' $CRONOS_SELECTOR $WETH9_CRONOS --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy" || true
[[ -n "$WETH10_CRONOS" ]] && run_or_echo "cast send $WETH10_138 'addDestination(uint64,address)' $CRONOS_SELECTOR $WETH10_CRONOS --rpc-url $CHAIN138_RPC --private-key \$PRIVATE_KEY --legacy" || true
fi
echo ""
echo "Step B: Avalanche/Arbitrum/Cronos → add Chain 138 as destination"
echo ""
# Step B: Avalanche → Chain 138
if [[ -n "$WETH9_AVALANCHE" || -n "$WETH10_AVALANCHE" ]]; then
echo " Avalanche → Chain 138:"
[[ -n "$WETH9_AVALANCHE" ]] && run_or_echo "cast send $WETH9_AVALANCHE 'addDestination(uint64,address)' $CHAIN138_SELECTOR $WETH9_138 --rpc-url $AVALANCHE_RPC --private-key \$PRIVATE_KEY --legacy" || true
[[ -n "$WETH10_AVALANCHE" ]] && run_or_echo "cast send $WETH10_AVALANCHE 'addDestination(uint64,address)' $CHAIN138_SELECTOR $WETH10_138 --rpc-url $AVALANCHE_RPC --private-key \$PRIVATE_KEY --legacy" || true
fi
# Step B: Arbitrum → Chain 138
if [[ -n "$WETH9_ARBITRUM" || -n "$WETH10_ARBITRUM" ]]; then
echo " Arbitrum → Chain 138:"
[[ -n "$WETH9_ARBITRUM" ]] && run_or_echo "cast send $WETH9_ARBITRUM 'addDestination(uint64,address)' $CHAIN138_SELECTOR $WETH9_138 --rpc-url $ARBITRUM_RPC --private-key \$PRIVATE_KEY --legacy" || true
[[ -n "$WETH10_ARBITRUM" ]] && run_or_echo "cast send $WETH10_ARBITRUM 'addDestination(uint64,address)' $CHAIN138_SELECTOR $WETH10_138 --rpc-url $ARBITRUM_RPC --private-key \$PRIVATE_KEY --legacy" || true
fi
# Step B: Cronos → Chain 138
if [[ -n "$WETH9_CRONOS" || -n "$WETH10_CRONOS" ]]; then
echo " Cronos → Chain 138:"
[[ -n "$WETH9_CRONOS" ]] && run_or_echo "cast send $WETH9_CRONOS 'addDestination(uint64,address)' $CHAIN138_SELECTOR $WETH9_138 --rpc-url $CRONOS_RPC --private-key \$PRIVATE_KEY --legacy" || true
[[ -n "$WETH10_CRONOS" ]] && run_or_echo "cast send $WETH10_CRONOS 'addDestination(uint64,address)' $CHAIN138_SELECTOR $WETH10_138 --rpc-url $CRONOS_RPC --private-key \$PRIVATE_KEY --legacy" || true
fi
echo ""
echo -e "${GREEN}Bridge configuration complete.${NC}"
echo "Next: Fund each bridge with LINK for CCIP fees if not already done."

View File

@@ -1,57 +1,107 @@
#!/usr/bin/env bash
# Configure bridge destinations for cross-chain functionality
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../lib/init.sh"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Configure Bridge Destinations Script
# Configures ChainID 138 ↔ Mainnet bidirectional bridge destinations
set -e
log_info "=== Configuring Bridge Destinations ==="
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Load environment
if [ -f "$PROJECT_ROOT/.env" ]; then
source "$PROJECT_ROOT/.env"
fi
# Configuration
PRIVATE_KEY="${PRIVATE_KEY:-}"
RPC_URL_138="${RPC_URL_138:-http://192.168.11.175:8545}"
RPC_URL_MAINNET="${RPC_URL_MAINNET:-https://eth.llamarpc.com}"
MAINNET_RPC="${ETHEREUM_MAINNET_RPC:-https://eth.llamarpc.com}"
CHAIN138_RPC="${RPC_URL:-https://rpc.d-bis.org}"
PRIVATE_KEY="${PRIVATE_KEY}"
if [[ ! "$PRIVATE_KEY" =~ ^0x ]]; then
PRIVATE_KEY="0x$PRIVATE_KEY"
fi
# Chain Selectors
MAINNET_CHAIN_SELECTOR="5009297550715157269"
CHAIN138_CHAIN_SELECTOR="${CHAIN138_CHAIN_SELECTOR:-}" # To be determined
# Get deployed addresses
WETH9_BRIDGE_MAINNET=$(grep "CCIPWETH9_BRIDGE_MAINNET=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "")
WETH10_BRIDGE_MAINNET=$(grep "CCIPWETH10_BRIDGE_MAINNET=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "")
WETH9_BRIDGE_CHAIN138=$(grep "CCIPWETH9_BRIDGE_CHAIN138=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "")
WETH10_BRIDGE_CHAIN138=$(grep "CCIPWETH10_BRIDGE_CHAIN138=" "$PROJECT_ROOT/.env" 2>/dev/null | cut -d'=' -f2 | tr -d ' "' || echo "")
# Contract Addresses (set these after deployment)
WETH9_BRIDGE_138="${WETH9_BRIDGE_138:-}"
WETH10_BRIDGE_138="${WETH10_BRIDGE_138:-}"
WETH9_MAINNET="${WETH9_MAINNET:-0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2}"
WETH10_MAINNET="${WETH10_MAINNET:-0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f}"
# Chain selectors
ETH_SELECTOR="${ETH_MAINNET_SELECTOR:-0x500147}" # Ethereum Mainnet
CHAIN138_SELECTOR="${CHAIN138_SELECTOR:-0x000000000000008a}" # Chain-138
echo -e "${GREEN}=== Bridge Destination Configuration ===${NC}\n"
echo "Configuration:"
echo " Ethereum Mainnet Selector: $ETH_SELECTOR"
echo " Chain-138 Selector: $CHAIN138_SELECTOR"
if [ -z "$WETH9_BRIDGE_MAINNET" ] || [ -z "$WETH9_BRIDGE_CHAIN138" ]; then
log_warn "⚠️ Bridge addresses not found in .env"
echo "Please ensure bridges are deployed on both chains"
# Check prerequisites
if [ -z "$PRIVATE_KEY" ]; then
echo -e "${RED}ERROR: PRIVATE_KEY environment variable not set${NC}"
exit 1
fi
echo "Bridge Addresses:"
echo " WETH9 Mainnet: $WETH9_BRIDGE_MAINNET"
echo " WETH9 Chain-138: $WETH9_BRIDGE_CHAIN138"
echo " WETH10 Mainnet: $WETH10_BRIDGE_MAINNET"
echo " WETH10 Chain-138: $WETH10_BRIDGE_CHAIN138"
if [ -z "$WETH9_BRIDGE_138" ] || [ -z "$WETH10_BRIDGE_138" ]; then
echo -e "${YELLOW}WARNING: Bridge addresses not set. Please set WETH9_BRIDGE_138 and WETH10_BRIDGE_138${NC}"
exit 1
fi
log_info "Note: Bridge destination configuration requires:"
echo " 1. Calling addDestination() on each bridge contract"
echo " 2. Setting the corresponding bridge address on the destination chain"
echo " 3. Enabling the destination"
echo "This can be done via:"
echo " • cast send (for Foundry)"
echo " • Hardhat scripts"
echo " • Direct contract interaction"
log_warn "⚠️ Manual configuration required"
# Function to add destination
add_destination() {
local bridge_address=$1
local chain_selector=$2
local destination_token=$3
local rpc_url=$4
local network_name=$5
echo -e "${GREEN}Adding destination to $network_name bridge...${NC}"
cast send "$bridge_address" \
"addDestination(uint64,address,address)" \
"$chain_selector" \
"$destination_token" \
"0x0000000000000000000000000000000000000000" \
--rpc-url "$rpc_url" \
--private-key "$PRIVATE_KEY" \
--legacy
echo -e "${GREEN}✓ Destination added${NC}\n"
}
# Function to verify destinations
verify_destinations() {
local bridge_address=$1
local rpc_url=$2
local network_name=$3
echo -e "${GREEN}Verifying destinations on $network_name...${NC}"
local chains=$(cast call "$bridge_address" \
"getDestinationChains()(uint64[])" \
--rpc-url "$rpc_url")
echo -e "${GREEN}Destination chains: $chains${NC}\n"
}
# Configure ChainID 138 → Mainnet
echo -e "${YELLOW}=== Configuring ChainID 138 → Mainnet ===${NC}\n"
echo -e "${GREEN}1. Configuring WETH9 Bridge (ChainID 138 → Mainnet)${NC}"
add_destination "$WETH9_BRIDGE_138" "$MAINNET_CHAIN_SELECTOR" "$WETH9_MAINNET" "$RPC_URL_138" "ChainID 138"
echo -e "${GREEN}2. Configuring WETH10 Bridge (ChainID 138 → Mainnet)${NC}"
add_destination "$WETH10_BRIDGE_138" "$MAINNET_CHAIN_SELECTOR" "$WETH10_MAINNET" "$RPC_URL_138" "ChainID 138"
# Verify ChainID 138 bridges
echo -e "${YELLOW}=== Verifying ChainID 138 Bridges ===${NC}\n"
verify_destinations "$WETH9_BRIDGE_138" "$RPC_URL_138" "WETH9 Bridge"
verify_destinations "$WETH10_BRIDGE_138" "$RPC_URL_138" "WETH10 Bridge"
# Note: Mainnet → ChainID 138 requires ChainID 138 selector
if [ -z "$CHAIN138_CHAIN_SELECTOR" ]; then
echo -e "${YELLOW}NOTE: ChainID 138 chain selector not set.${NC}"
echo -e "${YELLOW}To configure Mainnet → ChainID 138, first determine the ChainID 138 selector.${NC}"
echo -e "${YELLOW}You can find it using: cast call <CCIP_ROUTER> 'getChainSelector()(uint64)' --rpc-url $RPC_URL_138${NC}\n"
else
echo -e "${YELLOW}=== Configuring Mainnet → ChainID 138 ===${NC}\n"
echo -e "${YELLOW}NOTE: This requires deploying bridges on Mainnet first.${NC}\n"
fi
echo -e "${GREEN}=== Configuration Complete ===${NC}\n"
echo -e "Next Steps:"
echo -e " 1. Test bidirectional transfers"
echo -e " 2. Monitor bridge activity"
echo -e " 3. Verify LINK token balances for CCIP fees"

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Create a Uniswap V3 pool for cUSDT/cUSDC (or two token addresses) on a given chain.
# Requires: cast (foundry), RPC for the chain, PRIVATE_KEY with gas.
# Usage:
# CUSDT=0x... CUSDC=0x... RPC_URL=$POLYGON_MAINNET_RPC ./scripts/deployment/create-uniswap-v3-pool-cusdt-cusdc.sh
# Or: TOKEN_A=0x... TOKEN_B=0x... FEE=500 RPC_URL=... ./scripts/deployment/create-uniswap-v3-pool-cusdt-cusdc.sh
# Fee: 500 = 0.05% (typical for stables), 3000 = 0.3%, 10000 = 1%.
# Uniswap V3 factory (mainnet, Polygon, BSC, Base, Arbitrum, Optimism): 0x1F98431c8aD98523631AE4a59f267346ea31F984
# See docs/deployment/CUSDT_CUSDC_MULTICHAIN_LIQUIDITY_RUNBOOK.md
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
DOTENV="$REPO_ROOT/.env"
if [[ -f "$DOTENV" ]]; then set -a; source "$DOTENV"; set +a; fi
UNISWAP_V3_FACTORY="${UNISWAP_V3_FACTORY:-0x1F98431c8aD98523631AE4a59f267346ea31F984}"
FEE="${FEE:-500}"
TOKEN_A="${TOKEN_A:-${CUSDT_ADDRESS:-}}"
TOKEN_B="${TOKEN_B:-${CUSDC_ADDRESS:-}}"
if [[ -z "$TOKEN_A" ]] && [[ -n "${CUSDT_ADDRESS_137:-}" ]]; then
TOKEN_A="${CUSDT_ADDRESS_137}"
TOKEN_B="${CUSDC_ADDRESS_137}"
fi
if [[ -z "$TOKEN_A" ]]; then
echo "Set TOKEN_A and TOKEN_B (or CUSDT_ADDRESS and CUSDC_ADDRESS, or CUSDT_ADDRESS_<chainId> and CUSDC_ADDRESS_<chainId>)"
exit 1
fi
if [[ -z "$TOKEN_B" ]]; then
echo "Set TOKEN_B (or CUSDC_ADDRESS)"
exit 1
fi
RPC_URL="${RPC_URL:-${POLYGON_MAINNET_RPC:-${ETHEREUM_MAINNET_RPC:-}}}"
if [[ -z "$RPC_URL" ]]; then
echo "Set RPC_URL (or POLYGON_MAINNET_RPC / ETHEREUM_MAINNET_RPC)"
exit 1
fi
echo "Creating Uniswap V3 pool: tokenA=$TOKEN_A tokenB=$TOKEN_B fee=$FEE"
echo "Factory=$UNISWAP_V3_FACTORY RPC=$RPC_URL"
POOL=$(cast call "$UNISWAP_V3_FACTORY" "getPool(address,address,uint24)(address)" "$TOKEN_A" "$TOKEN_B" "$FEE" --rpc-url "$RPC_URL" 2>/dev/null || true)
if [[ -n "$POOL" ]] && [[ "$POOL" != "0x0000000000000000000000000000000000000000" ]]; then
echo "Pool already exists: $POOL"
exit 0
fi
cast send "$UNISWAP_V3_FACTORY" "createPool(address,address,uint24)" "$TOKEN_A" "$TOKEN_B" "$FEE" \
--rpc-url "$RPC_URL" \
--private-key "${PRIVATE_KEY:?PRIVATE_KEY required}"
POOL=$(cast call "$UNISWAP_V3_FACTORY" "getPool(address,address,uint24)(address)" "$TOKEN_A" "$TOKEN_B" "$FEE" --rpc-url "$RPC_URL")
echo "Pool created: $POOL"
echo "Next: initialize the pool with sqrtPriceX96 and add liquidity via Uniswap UI or NonfungiblePositionManager."

View File

@@ -8,7 +8,8 @@ cd "$PROJECT_ROOT"
source .env 2>/dev/null || true
RPC_URL="${RPC_URL:-http://localhost:8545}"
RPC_URL="${RPC_URL_138:-http://localhost:8545}"
GAS_PRICE="${GAS_PRICE:-1000000000}"
PRIVATE_KEY="${PRIVATE_KEY:-}"
if [ -z "$PRIVATE_KEY" ]; then
@@ -41,6 +42,7 @@ forge script script/DeployMulticall.s.sol:DeployMulticall \
--rpc-url "$RPC_URL" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "$GAS_PRICE" \
--legacy -vvv 2>&1 | tail -30
# Phase 3: Oracle Contracts
@@ -51,6 +53,7 @@ forge script script/DeployOracle.s.sol:DeployOracle \
--rpc-url "$RPC_URL" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "$GAS_PRICE" \
--legacy -vvv 2>&1 | tail -30
# Phase 4: Governance Contracts
@@ -61,6 +64,7 @@ forge script script/DeployMultiSig.s.sol:DeployMultiSig \
--rpc-url "$RPC_URL" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--with-gas-price "$GAS_PRICE" \
--legacy -vvv 2>&1 | tail -30
echo ""

View File

@@ -31,11 +31,13 @@ else
fi
# Configuration
# Use public RPC for broadcasting (Infura doesn't support private key transactions)
MAINNET_RPC="${MAINNET_RPC_URL:-https://eth.llamarpc.com}"
if [[ "$ETHEREUM_MAINNET_RPC" == *"infura.io"* ]]; then
log_warn "Note: Infura RPC doesn't support private key transactions, using public RPC"
MAINNET_RPC="https://eth.llamarpc.com"
# Use ETHEREUM_MAINNET_RPC; when Infura + INFURA_PROJECT_SECRET set, use Basic Auth URL for private key transactions
MAINNET_RPC="${MAINNET_RPC_URL:-${ETHEREUM_MAINNET_RPC:-https://eth.llamarpc.com}}"
if [[ "$MAINNET_RPC" == *"infura.io"* ]] && [[ -n "${INFURA_PROJECT_SECRET:-}" ]] && [[ ! "${INFURA_PROJECT_SECRET}" =~ \$\{ ]]; then
# Build Infura URL with Basic Auth so cast/forge can send transactions
[[ -f "$SCRIPT_DIR/../lib/infura.sh" ]] && source "$SCRIPT_DIR/../lib/infura.sh"
_with_auth=$(build_infura_rpc "mainnet" 2>/dev/null || true)
[[ -n "$_with_auth" ]] && MAINNET_RPC="$_with_auth" && log_info "Using Infura Mainnet RPC with Basic Auth"
fi
MAINNET_PRIVATE_KEY="${PRIVATE_KEY}"
MAINNET_CCIP_ROUTER="${MAINNET_CCIP_ROUTER:-0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D}" # Official Chainlink CCIP Router

View File

@@ -0,0 +1,157 @@
#!/usr/bin/env bash
# Deploy to all mainnets: CCIP Bridge, Trustless Bridge, Oracle, Mapper, PMM (anchored to ChainID 138).
# Run after check-balances-gas-and-deploy.sh. Requires .env with PRIVATE_KEY and per-chain RPC/CCIP vars.
# Usage: bash scripts/deployment/deploy-all-mainnets-with-mapper-oracle-pmm.sh [phase]
# phase: ccip | trustless | oracle | mapper | pmm | all (default: all)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
# Load .env without strict unset (avoid init.sh pipefail on .env)
set +u
[ -f .env ] && source .env
set -u
[ -f "$SCRIPT_DIR/../lib/infura.sh" ] && source "$SCRIPT_DIR/../lib/infura.sh"
PHASE="${1:-all}"
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
require_env() {
local var="$1"
if [ -z "${!var:-}" ]; then
echo -e "${RED}ERROR: $var not set in .env${NC}" >&2
return 1
fi
return 0
}
ensure_rpc() {
local rpc="$1"
type ensure_infura_rpc_url &>/dev/null && [ -n "$rpc" ] && rpc=$(ensure_infura_rpc_url "$rpc")
echo "$rpc"
}
# --- CCIP: DeployAll to BSC, Polygon, Base, Optimism, Gnosis ---
run_ccip_remaining_mainnets() {
echo -e "${YELLOW}=== CCIP Bridges (DeployAll) to BSC, Polygon, Base, Optimism, Gnosis ===${NC}"
require_env PRIVATE_KEY || return 1
local chains="BSC:56:BSC_RPC_URL POLYGON:137:POLYGON_MAINNET_RPC BASE:8453:BASE_MAINNET_RPC OPTIMISM:10:OPTIMISM_MAINNET_RPC GNOSIS:100:GNOSIS_MAINNET_RPC"
for entry in $chains; do
local name="${entry%%:*}"; entry="${entry#*:}"
local chain_id="${entry%%:*}"; entry="${entry#*:}"
local rpc_var="$entry"
local rpc="${!rpc_var:-}"
rpc=$(ensure_rpc "$rpc")
if [ -z "$rpc" ]; then
echo " Skip $name (no RPC)"
continue
fi
echo -e "${YELLOW}DeployAll to $name (chain $chain_id)...${NC}"
forge script script/DeployAll.s.sol:DeployAll \
--rpc-url "$rpc" --chain-id "$chain_id" --private-key "$PRIVATE_KEY" \
--broadcast --slow -vvv || echo -e "${RED}$name DeployAll failed${NC}"
echo ""
done
echo -e "${GREEN}CCIP phase done.${NC}"
}
# --- Trustless Bridge: Chain 138 (Lockbox) + Ethereum (BondManager, etc.) ---
run_trustless() {
echo -e "${YELLOW}=== Trustless Bridge (Chain 138 + Ethereum) ===${NC}"
require_env PRIVATE_KEY RPC_URL_138 || return 1
echo "Deploying Trustless (Lockbox) on Chain 138..."
forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \
--rpc-url "$RPC_URL_138" --broadcast --via-ir --private-key "$PRIVATE_KEY" -vvv || true
require_env ETHEREUM_MAINNET_RPC || return 1
MAINNET_RPC=$(ensure_rpc "$ETHEREUM_MAINNET_RPC")
echo "Deploying Trustless (BondManager, ChallengeManager, LP, Inbox, SwapRouter, Coordinator) on Ethereum..."
forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \
--rpc-url "$MAINNET_RPC" --broadcast --via-ir --private-key "$PRIVATE_KEY" \
${ETHERSCAN_API_KEY:+--verify --etherscan-api-key "$ETHERSCAN_API_KEY"} -vvv || true
echo -e "${GREEN}Trustless phase done.${NC}"
}
# --- Oracle: Chain 138 ---
run_oracle() {
echo -e "${YELLOW}=== Oracle (Chain 138) ===${NC}"
require_env PRIVATE_KEY RPC_URL_138 || return 1
forge script script/DeployOracle.s.sol:DeployOracle \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true
echo -e "${GREEN}Oracle phase done.${NC}"
}
# --- Mapper: Chain 138 (full) + others (empty) ---
run_mapper() {
echo -e "${YELLOW}=== Mapper (Chain 138 = AddressMapper; others = AddressMapperEmpty) ===${NC}"
require_env PRIVATE_KEY || return 1
if [ -n "${RPC_URL_138:-}" ]; then
echo "Deploying AddressMapper on Chain 138..."
forge script script/DeployAddressMapper.s.sol:DeployAddressMapper \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true
fi
local chains="ETHEREUM_MAINNET_RPC:1 BSC_RPC_URL:56 POLYGON_MAINNET_RPC:137 BASE_MAINNET_RPC:8453 ARBITRUM_MAINNET_RPC:42161 OPTIMISM_MAINNET_RPC:10 AVALANCHE_RPC_URL:43114 CRONOS_RPC_URL:25 GNOSIS_MAINNET_RPC:100"
for entry in $chains; do
local rpc_var="${entry%%:*}"; local chain_id="${entry#*:}"
local rpc="${!rpc_var:-}"
[ -z "$rpc" ] && continue
rpc=$(ensure_rpc "$rpc")
echo "Deploying AddressMapperEmpty on chain $chain_id..."
forge script script/DeployAddressMapperOtherChain.s.sol:DeployAddressMapperOtherChain \
--rpc-url "$rpc" --chain-id "$chain_id" --broadcast --private-key "$PRIVATE_KEY" -vvv || true
done
echo -e "${GREEN}Mapper phase done.${NC}"
}
# --- PMM (DODO) on Chain 138 ---
run_pmm() {
echo -e "${YELLOW}=== PMM Liquidity Pools (Chain 138) ===${NC}"
require_env PRIVATE_KEY RPC_URL_138 || return 1
if [ -z "${DODO_PMM_INTEGRATION:-}" ] && [ -n "${DODO_VENDING_MACHINE_ADDRESS:-}" ]; then
echo "Deploying DODOPMMIntegration on Chain 138..."
forge script script/dex/DeployDODOPMMIntegration.s.sol:DeployDODOPMMIntegration \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true
else
echo " DODOPMMIntegration already set or DODO_VENDING_MACHINE_ADDRESS not set; skip deploy."
fi
if [ -n "${DODO_PMM_INTEGRATION:-}" ] && [ -n "${XAU_ADDRESS:-}" ]; then
echo "Creating XAU-anchored pools..."
forge script script/dex/DeployPrivatePoolRegistryAndPools.s.sol:DeployPrivatePoolRegistryAndPools \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true
fi
echo -e "${GREEN}PMM phase done.${NC}"
}
# --- Main ---
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}All Mainnets: CCIP, Trustless, Oracle, Mapper, PMM${NC}"
echo -e "${GREEN}========================================${NC}"
echo "Phase: $PHASE"
echo ""
case "$PHASE" in
ccip) run_ccip_remaining_mainnets ;;
trustless) run_trustless ;;
oracle) run_oracle ;;
mapper) run_mapper ;;
pmm) run_pmm ;;
all)
run_ccip_remaining_mainnets
run_trustless
run_oracle
run_mapper
run_pmm
;;
*) echo "Usage: $0 [ccip|trustless|oracle|mapper|pmm|all]"; exit 1 ;;
esac
echo ""
echo -e "${GREEN}Done. Update .env and config/smart-contracts-master.json with any new addresses.${NC}"

View File

@@ -1,135 +1,115 @@
#!/bin/bash
#!/usr/bin/env bash
# Phased deployment for Chain 138: run each phase in order.
# Break-up of "deploy all" into discrete steps; skip phases that are already deployed (env set).
#
# Usage:
# ./scripts/deployment/deploy-all-phases.sh # run all phases (skip when env indicates done)
# ./scripts/deployment/deploy-all-phases.sh --all # run every phase (no skip)
# ./scripts/deployment/deploy-all-phases.sh --phase 5 # run only phase 5
# ./scripts/deployment/deploy-all-phases.sh --dry-run # print what would run
#
# Requires: .env with PRIVATE_KEY, RPC_URL_138 (Chain 138 Core). Uses --with-gas-price 1000000000 for Chain 138.
# Deploy All Phases
# This script orchestrates the complete deployment process
set -e
echo "=========================================="
echo " Trustless Bridge Complete Deployment"
echo "=========================================="
echo ""
# Load environment variables
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | grep -v '^$' | xargs)
else
echo "Error: .env file not found"
echo "Please run phase1-env-setup.sh first"
exit 1
fi
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
echo "This will deploy all phases of the trustless bridge system."
echo ""
read -p "Continue? (y/N) " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Deployment cancelled"
exit 1
if [ -f .env ]; then
set -a
source .env
set +a
fi
echo ""
echo "Starting deployment..."
echo ""
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
GAS_PRICE="${GAS_PRICE_138:-1000000000}"
DRY_RUN=""
RUN_ALL="" # if set, do not skip any phase
PHASE_ONLY="" # if set, run only this phase number (e.g. 5)
# Phase 1: Environment Setup
echo ">>> Phase 1: Environment Setup"
"$SCRIPT_DIR/phase1-env-setup.sh" || exit 1
echo ""
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY_RUN=1 ;;
--all) RUN_ALL=1 ;;
--phase)
shift
[ $# -gt 0 ] && PHASE_ONLY="$1"
;;
esac
shift
done
# Phase 2: Deploy Core Contracts
echo ">>> Phase 2: Deploy Core Bridge Contracts"
read -p "Deploy core contracts? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase2-deploy-core.sh" || exit 1
echo ""
read -p "Press Enter after updating .env with contract addresses..."
if [ -z "${PRIVATE_KEY:-}" ]; then
echo "ERROR: PRIVATE_KEY not set in .env"
exit 1
fi
run_phase() {
local num="$1"
local name="$2"
local skip_var="$3" # optional: if set in env, skip (unless --all)
local cmd="$4"
if [ -n "$PHASE_ONLY" ] && [ "$PHASE_ONLY" != "$num" ]; then
return 0
fi
if [ -n "$skip_var" ] && [ -z "$RUN_ALL" ]; then
local val=""
eval "val=\"\${${skip_var}:-}\""
if [ -n "$val" ]; then
echo "[Phase $num] $name — SKIP (${skip_var} already set)"
return 0
fi
fi
echo "[Phase $num] $name — RUNNING"
if [ -n "$DRY_RUN" ]; then
echo " would run: $(echo "$cmd" | sed 's/--private-key "[^"]*"/--private-key ***REDACTED***/g')"
return 0
fi
eval "$cmd" || { echo "Phase $num failed."; exit 1; }
echo "[Phase $num] $name — DONE"
}
echo "============================================"
echo "Chain 138 — Phased deployment"
echo "RPC: $RPC"
echo "Gas price: $GAS_PRICE wei"
echo "============================================"
echo ""
# Phase 3: Deploy Enhanced Router
echo ">>> Phase 3: Deploy EnhancedSwapRouter"
read -p "Deploy EnhancedSwapRouter? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase3-deploy-router.sh" || exit 1
echo ""
read -p "Press Enter after updating .env with ENHANCED_SWAP_ROUTER address..."
fi
echo ""
# Phase 1: Phased core (registry + governance)
run_phase 1 "Phased core (01_DeployCore)" "UNIVERSAL_ASSET_REGISTRY" \
"forge script script/deploy/01_DeployCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 4: Deploy Integration Contracts
echo ">>> Phase 4: Deploy Integration Contracts"
read -p "Deploy integration contracts? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase4-deploy-integration.sh" || exit 1
echo ""
read -p "Press Enter after updating .env with integration contract addresses..."
fi
echo ""
# Phase 2: Phased bridges (CCIP bridge + orchestrator)
run_phase 2 "Phased bridges (02_DeployBridges)" "UNIVERSAL_CCIP_BRIDGE" \
"forge script script/deploy/02_DeployBridges.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 5: Initialize System
echo ">>> Phase 5: Initialize System"
read -p "Initialize system? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase5-initialize.sh" || exit 1
fi
echo ""
# Phase 3: Channel managers
run_phase 3 "PaymentChannelManager" "PAYMENT_CHANNEL_MANAGER" \
"forge script script/DeployPaymentChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 6: Provide Liquidity
echo ">>> Phase 6: Provide Initial Liquidity"
read -p "Provide initial liquidity? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase6-provide-liquidity.sh" || exit 1
fi
echo ""
run_phase 3 "GenericStateChannelManager" "GENERIC_STATE_CHANNEL_MANAGER" \
"forge script script/DeployGenericStateChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 7: Configure
echo ">>> Phase 7: Configure Access Control and Routing"
read -p "Configure access control and routing? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase7-configure.sh" || exit 1
fi
echo ""
# Phase 4: Deterministic core (CREATE2)
run_phase 4 "Deterministic core (DeployDeterministicCore)" "CREATE2_FACTORY" \
"forge script script/deploy/DeployDeterministicCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 8: Deploy Services
echo ">>> Phase 8: Deploy Backend Services"
read -p "Deploy backend services? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase8-deploy-services.sh" || exit 1
fi
echo ""
# Phase 5: Vault system
run_phase 5 "Vault system (DeployVaultSystem)" "VAULT_FACTORY" \
"forge script script/deploy/vault/DeployVaultSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 9: Deploy Frontend
echo ">>> Phase 9: Deploy Frontend Applications"
read -p "Build frontend applications? (y/N) " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]; then
"$SCRIPT_DIR/phase9-deploy-frontend.sh" || exit 1
fi
echo ""
# Phase 6: Reserve system (requires TOKEN_FACTORY in .env)
run_phase 6 "Reserve system (DeployReserveSystem)" "RESERVE_SYSTEM" \
"forge script script/reserve/DeployReserveSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 10: Verify
echo ">>> Phase 10: Verification"
"$SCRIPT_DIR/phase10-verify.sh" || exit 1
# Phase 7: Trustless bridge (Lockbox138 on Chain 138)
run_phase 7 "Trustless bridge (Lockbox138)" "LOCKBOX_138" \
"forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
echo ""
echo "=========================================="
echo " Deployment Complete!"
echo "=========================================="
echo ""
echo "Next steps:"
echo "1. Review deployment status"
echo "2. Set up monitoring dashboards"
echo "3. Configure alerts"
echo "4. Train operations team"
echo "5. Begin bridge operations"
echo ""
echo "============================================"
echo "Phased deployment finished."
echo "Update .env with any new addresses and run setCCIPRouter on deterministic bridge if Phase 4 ran."
echo "============================================"

View File

@@ -0,0 +1,104 @@
#!/usr/bin/env bash
# Deploy CCIP WETH9/WETH10 bridges on Gnosis, Cronos, Celo, Wemix (config-ready chains).
# Requires: PRIVATE_KEY in .env; per-chain RPC and gas (xDAI, CRO, CELO, WEMIX).
# Set CCIP_ROUTER_<CHAIN>, LINK_TOKEN_<CHAIN>; set WETH9_<CHAIN> and WETH10_<CHAIN> (native wrapped token on each chain, or deployment will fail).
# See docs/deployment/ENV_CONFIG_READY_CHAINS.example and docs/07-ccip/CONFIG_READY_CHAINS_COMPLETION_RUNBOOK.md.
#
# Usage: cd smom-dbis-138 && ./scripts/deployment/deploy-bridges-config-ready-chains.sh [gnosis|cronos|celo|wemix|all]
# PREFLIGHT=1 ... # run preflight first (default: 1)
# DRY_RUN=1 ... # print forge commands only, no deploy
# SIMULATE=1 ... # run forge without --broadcast (test script, no on-chain tx)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
[[ -f "$PROJECT_ROOT/.env" ]] && set -a && source "$PROJECT_ROOT/.env" && set +a
DRY_RUN="${DRY_RUN:-0}"
SIMULATE="${SIMULATE:-0}"
PREFLIGHT="${PREFLIGHT:-1}"
CHAIN="${1:-all}"
# Per-chain env for DeployWETHBridges: RPC_URL, CCIP_ROUTER_ADDRESS, LINK_TOKEN_ADDRESS, WETH9_ADDRESS, WETH10_ADDRESS (0x0 to skip)
run_deploy() {
local chain_name="$1"
local rpc_var="$2"
local router_var="$3"
local link_var="$4"
local weth9_var="$5"
local weth10_var="$6"
local rpc="${!rpc_var:-}"
local router="${!router_var:-}"
local link="${!link_var:-}"
local weth9="${!weth9_var:-}"
local weth10="${!weth10_var:-}"
if [[ -z "$rpc" || -z "$router" ]]; then
echo " Skip $chain_name: set ${rpc_var} and ${router_var} in .env"
return 0
fi
if [[ -z "${PRIVATE_KEY:-}" ]]; then
echo " Skip $chain_name: PRIVATE_KEY not set"
return 0
fi
if [[ -z "$weth9" || -z "$weth10" ]]; then
echo " Skip $chain_name: set ${weth9_var} and ${weth10_var} in .env (native wrapped token addresses from chain)"
return 0
fi
export RPC_URL="$rpc"
export CCIP_ROUTER_ADDRESS="$router"
export LINK_TOKEN_ADDRESS="${link:-0x0000000000000000000000000000000000000000}"
export WETH9_ADDRESS="$weth9"
export WETH10_ADDRESS="$weth10"
local broadcast="--broadcast"
[[ "$SIMULATE" == "1" ]] && broadcast=""
local cmd="forge script script/deploy/bridge/DeployWETHBridges.s.sol:DeployWETHBridges --rpc-url \"$RPC_URL\" $broadcast --legacy -vvvv"
if [[ "$DRY_RUN" == "1" ]]; then
echo " [DRY RUN] $chain_name: $cmd"
return 0
fi
if [[ "$SIMULATE" == "1" ]]; then
echo " Simulating deploy on $chain_name (no broadcast)..."
else
echo " Deploying bridges on $chain_name..."
fi
eval "$cmd" || { echo " Failed (non-fatal)"; return 0; }
echo " Set CCIPWETH9_BRIDGE_${chain_name^^} and CCIPWETH10_BRIDGE_${chain_name^^} in .env from script output."
}
# Preflight (RPC + gas balance check)
if [[ "$PREFLIGHT" == "1" && "$DRY_RUN" != "1" ]]; then
if ! "$SCRIPT_DIR/preflight-config-ready-chains.sh" "$CHAIN" 2>/dev/null; then
echo ""
echo "Preflight failed. Fix RPCs and gas balances, or run with PREFLIGHT=0 to skip."
exit 1
fi
echo ""
fi
echo "=== Deploy CCIP bridges (Gnosis, Cronos, Celo, Wemix) ==="
echo " DRY_RUN=$DRY_RUN SIMULATE=$SIMULATE PREFLIGHT=$PREFLIGHT CHAIN=$CHAIN"
echo " Gas tokens: Gnosis=xDAI, Cronos=CRO, Celo=CELO, Wemix=WEMIX"
echo ""
case "$CHAIN" in
gnosis) run_deploy "GNOSIS" "GNOSIS_RPC" "CCIP_ROUTER_GNOSIS" "LINK_TOKEN_GNOSIS" "WETH9_GNOSIS" "WETH10_GNOSIS" ;;
cronos) run_deploy "CRONOS" "CRONOS_RPC" "CCIP_ROUTER_CRONOS" "LINK_TOKEN_CRONOS" "WETH9_CRONOS" "WETH10_CRONOS" ;;
celo) run_deploy "CELO" "CELO_RPC" "CCIP_ROUTER_CELO" "LINK_TOKEN_CELO" "WETH9_CELO" "WETH10_CELO" ;;
wemix) run_deploy "WEMIX" "WEMIX_RPC" "CCIP_ROUTER_WEMIX" "LINK_TOKEN_WEMIX" "WETH9_WEMIX" "WETH10_WEMIX" ;;
all)
run_deploy "GNOSIS" "GNOSIS_RPC" "CCIP_ROUTER_GNOSIS" "LINK_TOKEN_GNOSIS" "WETH9_GNOSIS" "WETH10_GNOSIS"
run_deploy "CRONOS" "CRONOS_RPC" "CCIP_ROUTER_CRONOS" "LINK_TOKEN_CRONOS" "WETH9_CRONOS" "WETH10_CRONOS"
run_deploy "CELO" "CELO_RPC" "CCIP_ROUTER_CELO" "LINK_TOKEN_CELO" "WETH9_CELO" "WETH10_CELO"
run_deploy "WEMIX" "WEMIX_RPC" "CCIP_ROUTER_WEMIX" "LINK_TOKEN_WEMIX" "WETH9_WEMIX" "WETH10_WEMIX"
;;
*) echo "Usage: $0 [gnosis|cronos|celo|wemix|all]"; exit 1 ;;
esac
echo ""
echo "Next: Add deployed bridge addresses to .env (CCIPWETH9_BRIDGE_*, CCIPWETH10_BRIDGE_*), then run complete-config-ready-chains.sh"

View File

@@ -0,0 +1,41 @@
#!/usr/bin/env bash
# Deploy CCIPLogger to all configured chains (mainnet, BSC, Polygon, Gnosis, Cronos) via Hardhat.
# Requires: from smom-dbis-138 run `pnpm install` or `npm install` so Hardhat resolves locally; .env with PRIVATE_KEY and per-chain RPC.
# Usage: cd smom-dbis-138 && ./scripts/deployment/deploy-ccip-logger-all-chains.sh
# CHAINS="mainnet bsc" ./scripts/deployment/deploy-ccip-logger-all-chains.sh # only mainnet and bsc
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
if [[ -f .env ]]; then
set -a
source .env
set +a
fi
CHAINS="${CHAINS:-mainnet bsc polygon gnosis cronos}"
if ! command -v npx &>/dev/null; then
echo "npx not found. Install Node/npm and run: npm install" >&2
exit 1
fi
echo "Deploying CCIPLogger to: $CHAINS"
for net in $CHAINS; do
echo ""
echo "=== $net ==="
case "$net" in
mainnet) npm run deploy:logger:mainnet 2>&1 || echo " Failed (non-fatal)" ;;
bsc) NETWORK=bsc npx hardhat run scripts/ccip-deployment/deploy-ccip-logger-multichain.js --network bsc 2>&1 || echo " Failed (non-fatal)" ;;
polygon) npm run deploy:logger:polygon 2>&1 || echo " Failed (non-fatal)" ;;
gnosis) npm run deploy:logger:gnosis 2>&1 || echo " Failed (non-fatal)" ;;
cronos) npm run deploy:logger:cronos 2>&1 || echo " Failed (non-fatal)" ;;
*) echo " Unknown network: $net" ;;
esac
done
echo ""
echo "Done. Update .env with CCIP_LOGGER_* addresses per chain if deployed."

View File

@@ -87,8 +87,8 @@ fi
# Verify RPC endpoint
log_info "Verifying RPC endpoint..."
if ! curl -s -X POST "$RPC_URL" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' > /dev/null 2>&1; then
log_error "Error: RPC endpoint is not accessible"
if ! curl -s -m 10 -X POST "$RPC_URL" -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' > /dev/null 2>&1; then
log_error "Error: RPC endpoint is not accessible at $RPC_URL"
exit 1
fi

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bash
# Deploy CompliantUSDT and CompliantUSDC to each target chain (Ethereum, BSC, Polygon, Base, etc.).
# Uses smom-dbis-138/.env. Requires per-chain RPC and PRIVATE_KEY with gas on each chain.
# Output: suggested .env lines for CUSDT_ADDRESS_<chainId> and CUSDC_ADDRESS_<chainId>.
# See docs/deployment/CUSDT_CUSDC_MULTICHAIN_LIQUIDITY_RUNBOOK.md
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
DOTENV="$REPO_ROOT/.env"
cd "$REPO_ROOT"
if [[ -f "$DOTENV" ]]; then set -a; source "$DOTENV"; set +a; fi
# Chain name : chain_id : RPC env var name
CHAINS=(
"ETHEREUM:1:ETHEREUM_MAINNET_RPC"
"BSC:56:BSC_RPC_URL"
"POLYGON:137:POLYGON_MAINNET_RPC"
"BASE:8453:BASE_MAINNET_RPC"
"OPTIMISM:10:OPTIMISM_MAINNET_RPC"
"ARBITRUM:42161:ARBITRUM_MAINNET_RPC"
"AVALANCHE:43114:AVALANCHE_RPC_URL"
"CRONOS:25:CRONOS_RPC_URL"
"GNOSIS:100:GNOSIS_MAINNET_RPC"
"CELO:42220:CELO_MAINNET_RPC"
"WEMIX:1111:WEMIX_MAINNET_RPC"
)
FILTER="${DEPLOY_CUSDT_CUSDC_FILTER:-}"
DRY_RUN="${DEPLOY_CUSDT_CUSDC_DRY_RUN:-}"
for entry in "${CHAINS[@]}"; do
IFS=: read -r name chain_id rpc_var <<< "$entry"
if [[ -n "$FILTER" ]] && [[ " $FILTER " != *" $name "* ]]; then continue; fi
rpc="${!rpc_var:-}"
if [[ -z "$rpc" ]]; then
echo "Skip $name (chain $chain_id): $rpc_var not set"
continue
fi
echo "=== $name (chain $chain_id) ==="
if [[ -n "$DRY_RUN" ]]; then
echo "[DRY RUN] Would deploy CompliantUSDT and CompliantUSDC on $name via $rpc_var"
continue
fi
CUSDT=""
CUSDC=""
log_usdt="/tmp/cusdt-deploy-$chain_id.log"
log_usdc="/tmp/cusdc-deploy-$chain_id.log"
if forge script script/DeployCompliantUSDT.s.sol:DeployCompliantUSDT \
--rpc-url "$rpc" \
--chain-id "$chain_id" \
--broadcast \
--private-key "${PRIVATE_KEY:?PRIVATE_KEY required}" \
-vv 2>&1 | tee "$log_usdt"; then
CUSDT=$(grep -oE "CompliantUSDT deployed at: 0x[a-fA-F0-9]{40}" "$log_usdt" | tail -1 | awk '{print $NF}')
fi
if [[ -z "$CUSDT" ]]; then
echo "Warning: CompliantUSDT deploy failed or address not found on $name"
else
echo "CUSDT_ADDRESS_${chain_id}=$CUSDT"
fi
if forge script script/DeployCompliantUSDC.s.sol:DeployCompliantUSDC \
--rpc-url "$rpc" \
--chain-id "$chain_id" \
--broadcast \
--private-key "${PRIVATE_KEY:?PRIVATE_KEY required}" \
-vv 2>&1 | tee "$log_usdc"; then
CUSDC=$(grep -oE "CompliantUSDC deployed at: 0x[a-fA-F0-9]{40}" "$log_usdc" | tail -1 | awk '{print $NF}')
fi
if [[ -z "$CUSDC" ]]; then
echo "Warning: CompliantUSDC deploy failed or address not found on $name"
else
echo "CUSDC_ADDRESS_${chain_id}=$CUSDC"
fi
echo ""
done
echo "Done. Add the printed CUSDT_ADDRESS_<id> and CUSDC_ADDRESS_<id> lines to .env."
echo "See docs/deployment/CUSDT_CUSDC_MULTICHAIN_LIQUIDITY_RUNBOOK.md for next steps (PMM, Uniswap, Balancer, Curve)."

View File

@@ -0,0 +1,182 @@
#!/usr/bin/env bash
# Create LXC 5801 (dapp-smom): frontend-dapp build served by nginx.
# Usage: ./scripts/deployment/deploy-dapp-lxc.sh [--dry-run] [--skip-create]
# --dry-run Print commands only.
# --skip-create Use existing container 5801 (only install/build/serve).
# Env: PROXMOX_HOST (optional; if unset, run pct on current host), NODE (optional; pct --node),
# VMID, HOSTNAME, IP_DAPP_LXC, TEMPLATE, STORAGE, NETWORK, MEMORY_MB, CORES, DISK_GB,
# REPO_URL (git URL to clone) or REPO_PATH (local path to copy; no git in container),
# ENV_FILE (path to .env for VITE_*).
# See: docs/03-deployment/DAPP_LXC_DEPLOYMENT.md
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SMOM_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Robust ip-addresses.conf path: override, or proxmox repo layout, or smom-dbis-138-only layout
IP_CONFIG_PATH="${IP_CONFIG_PATH:-}"
if [[ -n "$IP_CONFIG_PATH" && -f "$IP_CONFIG_PATH" ]]; then
source "$IP_CONFIG_PATH" 2>/dev/null || true
elif [[ -f "${SMOM_ROOT}/../../config/ip-addresses.conf" ]]; then
source "${SMOM_ROOT}/../../config/ip-addresses.conf" 2>/dev/null || true
elif [[ -f "${SCRIPT_DIR}/../../../config/ip-addresses.conf" ]]; then
source "${SCRIPT_DIR}/../../../config/ip-addresses.conf" 2>/dev/null || true
fi
VMID="${VMID:-5801}"
HOSTNAME="${HOSTNAME:-dapp-smom}"
IP="${IP_DAPP_LXC:-192.168.11.58}"
GATEWAY="${NETWORK_GATEWAY:-192.168.11.1}"
NETWORK="${NETWORK:-vmbr0}"
STORAGE="${STORAGE:-local-lvm}"
TEMPLATE="${TEMPLATE:-local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst}"
MEMORY_MB="${MEMORY_MB:-6144}"
CORES="${CORES:-4}"
DISK_GB="${DISK_GB:-40}"
REPO_URL="${REPO_URL:-}"
REPO_PATH="${REPO_PATH:-}"
ENV_FILE="${ENV_FILE:-}"
PROXMOX_HOST="${PROXMOX_HOST:-}"
NODE="${NODE:-}"
SSH_OPTS="-o ConnectTimeout=15 -o StrictHostKeyChecking=accept-new"
DRY_RUN=false
SKIP_CREATE=false
for a in "$@"; do
[[ "$a" == "--dry-run" ]] && DRY_RUN=true
[[ "$a" == "--skip-create" ]] && SKIP_CREATE=true
done
run_cmd() {
if [[ -n "$PROXMOX_HOST" ]]; then
ssh $SSH_OPTS root@"$PROXMOX_HOST" "$@"
else
bash -c "$*"
fi
}
run_pct() {
local node_opt=""
[[ -n "$NODE" && -z "$PROXMOX_HOST" ]] && node_opt="--node $NODE"
if [[ -n "$PROXMOX_HOST" ]]; then
ssh $SSH_OPTS root@"$PROXMOX_HOST" "pct $node_opt $*"
else
pct $node_opt "$@"
fi
}
pct_exec() {
run_pct "exec $VMID -- $*"
}
echo "=== DApp LXC ($VMID) — $HOSTNAME ==="
echo "IP: $IP | Memory: ${MEMORY_MB}MB | Cores: $CORES | Disk: ${DISK_GB}G"
echo ""
if ! $SKIP_CREATE; then
if $DRY_RUN; then
echo "[DRY-RUN] Would create LXC $VMID on ${PROXMOX_HOST:-local} with hostname=$HOSTNAME, ip=$IP/24"
exit 0
fi
if run_pct list 2>/dev/null | grep -q " $VMID "; then
echo "Container $VMID already exists. Use --skip-create to only install/build/serve."
exit 0
fi
echo "Creating CT $VMID ($HOSTNAME)..."
# When PROXMOX_HOST is set we SSH to that host; do not pass --node (pct runs on that node).
node_opt=""
[[ -n "$NODE" && -z "$PROXMOX_HOST" ]] && node_opt="--node $NODE"
run_cmd "pct create $VMID $TEMPLATE \
--hostname $HOSTNAME \
--memory $MEMORY_MB \
--cores $CORES \
--rootfs $STORAGE:${DISK_GB} \
--net0 name=eth0,bridge=$NETWORK,ip=$IP/24,gw=$GATEWAY \
--nameserver ${DNS_PRIMARY:-1.1.1.1} \
--description 'DApp (frontend-dapp) for Chain 138 bridge. See docs/03-deployment/DAPP_LXC_DEPLOYMENT.md' \
--start 1 \
--onboot 1 \
--unprivileged 0 \
--features nesting=1 \
$node_opt"
echo "Waiting for container to boot..."
sleep 20
fi
if $DRY_RUN; then
echo "[DRY-RUN] Would install Node, nginx, clone repo, build, configure nginx."
exit 0
fi
echo "Installing Node 20, nginx, git, curl..."
pct_exec "bash -c 'export DEBIAN_FRONTEND=noninteractive && apt-get update -qq && apt-get install -y -qq curl git ca-certificates'"
pct_exec "bash -c 'curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y -qq nodejs'"
pct_exec "apt-get install -y -qq nginx"
if [[ -z "$REPO_URL" && -z "$REPO_PATH" ]]; then
echo "Neither REPO_URL nor REPO_PATH set. Skipping clone/copy and build."
echo "Example: REPO_URL=https://github.com/your-org/smom-dbis-138.git ... or REPO_PATH=/path/to/smom-dbis-138 ... ./scripts/deployment/deploy-dapp-lxc.sh --skip-create"
exit 0
fi
APP_DIR="/srv/smom-dbis-138"
pct_exec "mkdir -p $APP_DIR"
if [[ -n "$REPO_PATH" && -d "$REPO_PATH" ]]; then
echo "Copying repo from host ($REPO_PATH)..."
PARENT="$(cd "$(dirname "$REPO_PATH")" && pwd)"
BARE="$(basename "$REPO_PATH")"
TARNAME="smom-dbis-138-deploy.tar.gz"
TARBALL="/tmp/$TARNAME"
(cd "$PARENT" && tar czf "$TARBALL" --exclude="$BARE/node_modules" --exclude="$BARE/.git" --exclude="$BARE/frontend-dapp/node_modules" --exclude="$BARE/frontend-dapp/dist" "$BARE") || { echo "Failed to create tarball"; exit 1; }
if [[ -n "$PROXMOX_HOST" ]]; then
scp $SSH_OPTS "$TARBALL" root@"$PROXMOX_HOST":/tmp/
run_cmd "pct push $VMID /tmp/$TARNAME /tmp/$TARNAME"
pct_exec "bash -c 'rm -rf $APP_DIR && mkdir -p /srv && tar xzf /tmp/$TARNAME -C /srv && rm /tmp/$TARNAME'"
run_cmd "rm -f /tmp/$TARNAME"
else
run_pct push "$VMID" "$TARBALL" "/tmp/$TARNAME"
pct_exec "bash -c 'rm -rf $APP_DIR && mkdir -p /srv && tar xzf /tmp/$TARNAME -C /srv && rm /tmp/$TARNAME'"
fi
rm -f "$TARBALL"
elif [[ -n "$REPO_URL" ]]; then
echo "Cloning repo..."
pct_exec "bash -c 'if [ -d $APP_DIR/.git ]; then (cd $APP_DIR && git fetch && git reset --hard origin/HEAD); else git clone --depth 1 $REPO_URL $APP_DIR; fi'"
fi
if [[ -n "$ENV_FILE" && -f "$ENV_FILE" ]]; then
if [[ -n "$PROXMOX_HOST" ]]; then
REMOTE_ENV="/tmp/dapp-deploy-$$.env"
echo "Copying .env to Proxmox host and pushing into container..."
scp $SSH_OPTS "$ENV_FILE" root@"$PROXMOX_HOST":"$REMOTE_ENV" && \
run_pct push "$VMID" "$REMOTE_ENV" "$APP_DIR/.env" 2>/dev/null || true
run_cmd "rm -f $REMOTE_ENV" 2>/dev/null || true
else
run_pct push "$VMID" "$ENV_FILE" "$APP_DIR/.env" 2>/dev/null || true
fi
fi
echo "Building frontend-dapp..."
pct_exec "bash -c 'cd $APP_DIR/frontend-dapp && (test -f package-lock.json && npm ci || npm install) && npm run build'"
echo "Configuring nginx to serve dist..."
pct_exec "bash -c 'cat > /etc/nginx/sites-available/dapp <<\"NGINXEOF\"
server {
listen 80 default_server;
listen [::]:80 default_server;
root /srv/smom-dbis-138/frontend-dapp/dist;
index index.html;
server_name _;
include /srv/smom-dbis-138/frontend-dapp/nginx-dapp-snippet.conf;
location / {
try_files \$uri \$uri/ /index.html;
}
}
NGINXEOF
rm -f /etc/nginx/sites-enabled/default && ln -sf /etc/nginx/sites-available/dapp /etc/nginx/sites-enabled/dapp && nginx -t && systemctl reload nginx'"
echo "Done. DApp LXC $VMID ($HOSTNAME) is serving at http://$IP"
echo "Add NPMplus proxy host (e.g. dapp.d-bis.org) pointing to $IP:80. See docs/03-deployment/DAPP_LXC_DEPLOYMENT.md"

View File

@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Full parity: Mapper + Oracle on ALL bridge networks.
# Extends deploy-all-mainnets-with-mapper-oracle-pmm.sh with Celo, Wemix, and Oracle-on-all-chains.
# Usage: bash scripts/deployment/deploy-full-parity-all-chains.sh [phase] [--dry-run]
# phase: mapper | oracle | bridges | all (default: all)
# --dry-run Print commands only
# Requires: .env with PRIVATE_KEY and per-chain RPC vars (GNOSIS_RPC, CELO_RPC, WEMIX_RPC, etc.)
# See: docs/07-ccip/FULL_PARITY_RUNBOOK.md
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
set +u
[ -f .env ] && source .env
set -u
[ -f "$SCRIPT_DIR/../lib/infura.sh" ] && source "$SCRIPT_DIR/../lib/infura.sh"
PHASE="${1:-all}"
DRY_RUN=false
for a in "$@"; do [[ "$a" == "--dry-run" ]] && DRY_RUN=true; done
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
ensure_rpc() {
local rpc="$1"
type ensure_infura_rpc_url &>/dev/null && [ -n "$rpc" ] && rpc=$(ensure_infura_rpc_url "$rpc")
echo "$rpc"
}
run_or_echo() {
if $DRY_RUN; then
echo " [DRY RUN] $*"
else
eval "$@" || echo -e "${RED} Failed${NC}"
fi
}
# --- Mapper: all chains including Celo, Wemix ---
run_mapper() {
echo -e "${YELLOW}=== Full Parity: Mapper (AddressMapperEmpty) on ALL bridge chains ===${NC}"
[ -z "${PRIVATE_KEY:-}" ] && { echo -e "${RED}PRIVATE_KEY not set${NC}"; return 1; }
# RPC_VAR:CHAIN_ID — include Celo, Wemix
local chains="ETHEREUM_MAINNET_RPC:1 BSC_RPC_URL:56 POLYGON_MAINNET_RPC:137 BASE_MAINNET_RPC:8453 ARBITRUM_MAINNET_RPC:42161 OPTIMISM_MAINNET_RPC:10 AVALANCHE_RPC_URL:43114 CRONOS_RPC_URL:25 GNOSIS_RPC:100 CELO_RPC:42220 WEMIX_RPC:1111"
for entry in $chains; do
local rpc_var="${entry%%:*}"; local chain_id="${entry#*:}"
local rpc="${!rpc_var:-}"
[ -z "$rpc" ] && echo " Skip chain $chain_id ($rpc_var not set)" && continue
rpc=$(ensure_rpc "$rpc")
echo " Deploying AddressMapperEmpty on chain $chain_id ($rpc_var)..."
local gas_opts=""
[ "$chain_id" = "138" ] && gas_opts="--with-gas-price ${GAS_PRICE_138:-1000000000} --legacy"
run_or_echo "forge script script/DeployAddressMapperOtherChain.s.sol:DeployAddressMapperOtherChain --rpc-url \"$rpc\" --chain-id \"$chain_id\" --broadcast --private-key \"\$PRIVATE_KEY\" $gas_opts -vvv"
done
echo -e "${GREEN}Mapper phase done. Record addresses in config.${NC}"
}
# --- Oracle: all chains ---
run_oracle() {
echo -e "${YELLOW}=== Full Parity: Oracle (Aggregator+Proxy) on ALL bridge chains ===${NC}"
[ -z "${PRIVATE_KEY:-}" ] && { echo -e "${RED}PRIVATE_KEY not set${NC}"; return 1; }
local chains="RPC_URL_138:138 ETHEREUM_MAINNET_RPC:1 BSC_RPC_URL:56 POLYGON_MAINNET_RPC:137 BASE_MAINNET_RPC:8453 ARBITRUM_MAINNET_RPC:42161 OPTIMISM_MAINNET_RPC:10 AVALANCHE_RPC_URL:43114 CRONOS_RPC_URL:25 GNOSIS_RPC:100 CELO_RPC:42220 WEMIX_RPC:1111"
for entry in $chains; do
local rpc_var="${entry%%:*}"; local chain_id="${entry#*:}"
local rpc="${!rpc_var:-}"
[ -z "$rpc" ] && echo " Skip chain $chain_id ($rpc_var not set)" && continue
rpc=$(ensure_rpc "$rpc")
echo " Deploying Oracle on chain $chain_id ($rpc_var)..."
local gas_opts=""
[ "$chain_id" = "138" ] && gas_opts="--with-gas-price ${GAS_PRICE_138:-1000000000} --legacy"
run_or_echo "forge script script/DeployOracle.s.sol:DeployOracle --rpc-url \"$rpc\" --broadcast --private-key \"\$PRIVATE_KEY\" $gas_opts -vvv"
done
echo -e "${GREEN}Oracle phase done. Record Aggregator+Proxy addresses in config.${NC}"
}
# --- Bridges: Celo, Wemix (when funded) ---
run_bridges() {
echo -e "${YELLOW}=== Full Parity: CCIP Bridges on Celo, Wemix ===${NC}"
[ -z "${PRIVATE_KEY:-}" ] && { echo -e "${RED}PRIVATE_KEY not set${NC}"; return 1; }
run_or_echo "bash scripts/deployment/deploy-bridges-config-ready-chains.sh celo"
run_or_echo "bash scripts/deployment/deploy-bridges-config-ready-chains.sh wemix"
echo " Run complete-config-ready-chains.sh after recording bridge addresses in .env"
echo -e "${GREEN}Bridges phase done.${NC}"
}
# --- Main ---
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Full Parity: Mapper, Oracle, AMB on All Bridge Networks${NC}"
echo -e "${GREEN}========================================${NC}"
echo "Phase: $PHASE Dry-run: $DRY_RUN"
echo ""
case "$PHASE" in
mapper) run_mapper ;;
oracle) run_oracle ;;
bridges) run_bridges ;;
all)
run_bridges
run_mapper
run_oracle
;;
*) echo "Usage: $0 [mapper|oracle|bridges|all] [--dry-run]"; exit 1 ;;
esac
echo ""
echo -e "${GREEN}Done. Update .env and config with new addresses. See docs/07-ccip/FULL_PARITY_RUNBOOK.md${NC}"

View File

@@ -49,7 +49,7 @@ if ! cast block-number --rpc-url "$ETHEREUM_MAINNET_RPC" >/dev/null 2>&1; then
echo ""
echo "Please fix the Infura RPC configuration:"
echo " 1. Go to https://infura.io/"
echo " 2. Project ID: 43b945b33d58463a9246cf5ca8aa6286"
echo " 2. Project ID: (set in .env as INFURA_PROJECT_ID; use INFURA_PROJECT_SECRET for Basic Auth)"
echo " 3. Settings → Disable 'Private Key Only'"
echo " 4. Save and run this script again"
echo ""

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bash
# Deploy official DODO DVM (DVMFactory + deps) to Chain 138 via DODOEX/contractV2 Truffle,
# then deploy DVMFactoryAdapter (createDVM -> createDODOVendingMachine) via Forge and update .env.
# Requires: smom-dbis-138/.env with PRIVATE_KEY, RPC_URL_138
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
DODO_DIR="$PROJECT_ROOT/lib/dodo-contractV2"
cd "$PROJECT_ROOT"
if [[ ! -f .env ]]; then
echo "ERROR: .env not found" >&2
exit 1
fi
set -a
source .env
set +a
if [[ -z "${PRIVATE_KEY:-}" ]]; then
echo "ERROR: PRIVATE_KEY not set" >&2
exit 1
fi
if [[ -z "${RPC_URL_138:-}" ]]; then
echo "ERROR: RPC_URL_138 not set" >&2
exit 1
fi
# Ensure DODO submodule has deps and compiles
if [[ ! -d "$DODO_DIR/node_modules" ]]; then
echo "Installing DODO contractV2 dependencies..."
(cd "$DODO_DIR" && npm install)
fi
# Export for Truffle (privKey without 0x for HDWalletProvider if needed)
export privKey="${PRIVATE_KEY#0x}"
export RPC_URL_138
export GAS_PRICE_138="${GAS_PRICE_138:-1000000000}"
# Deploy Migrations (required for Truffle), then DVM stack only
echo "=== Running Truffle migration 1 (Migrations) on Chain 138 ==="
(cd "$DODO_DIR" && npx truffle migrate -f 1 --to 1 --network chain138) || true
echo "=== Running Truffle migration 9 (DVM stack) on Chain 138 ==="
(cd "$DODO_DIR" && npx truffle migrate -f 9 --to 9 --network chain138)
# Parse DVMFactory address from Truffle build (network id 138 as string or number)
DVM_FACTORY_ADDRESS=$(cd "$DODO_DIR" && node -e "
const fs = require('fs');
const path = require('path');
const buildPath = path.join(__dirname, 'build', 'contracts', 'DVMFactory.json');
if (!fs.existsSync(buildPath)) process.exit(1);
const j = JSON.parse(fs.readFileSync(buildPath, 'utf8'));
const n = j.networks || {};
const addr = n['138']?.address || n[138]?.address;
if (!addr) process.exit(1);
console.log(addr);
" 2>/dev/null) || true
if [[ -z "$DVM_FACTORY_ADDRESS" ]]; then
echo "Could not read DVMFactory from build. If you already deployed, set DODO_DVM_FACTORY and run:" >&2
echo " DODO_DVM_FACTORY=<dvm_factory_address> forge script script/dex/DeployDVMFactoryAdapter.s.sol:DeployDVMFactoryAdapter --rpc-url \$RPC_URL_138 --broadcast --private-key \$PRIVATE_KEY --legacy" >&2
exit 1
fi
echo "DVMFactory deployed at: $DVM_FACTORY_ADDRESS"
echo "=== Deploying DVMFactoryAdapter (createDVM wrapper) via Forge ==="
export DODO_DVM_FACTORY="$DVM_FACTORY_ADDRESS"
forge script script/dex/DeployDVMFactoryAdapter.s.sol:DeployDVMFactoryAdapter \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" --legacy
# Extract adapter address from broadcast (or script output)
ADAPTER_ADDRESS=$(grep -o '"contractAddress":"0x[^"]*"' "$PROJECT_ROOT/broadcast/DeployDVMFactoryAdapter.s.sol/138/"*run-latest.json 2>/dev/null | tail -1 | sed 's/.*"0x/0x/;s/".*//') || true
if [[ -z "$ADAPTER_ADDRESS" ]]; then
echo "Set DODO_VENDING_MACHINE_ADDRESS to the DVMFactoryAdapter address printed above."
exit 0
fi
echo "DVMFactoryAdapter at: $ADAPTER_ADDRESS"
echo "Updating .env DODO_VENDING_MACHINE_ADDRESS=$ADAPTER_ADDRESS"
if grep -q '^DODO_VENDING_MACHINE_ADDRESS=' .env; then
sed -i "s|^DODO_VENDING_MACHINE_ADDRESS=.*|DODO_VENDING_MACHINE_ADDRESS=$ADAPTER_ADDRESS|" .env
else
echo "DODO_VENDING_MACHINE_ADDRESS=$ADAPTER_ADDRESS" >> .env
fi
echo "Done. Run scripts/deployment/run-pmm-and-pools.sh to deploy DODOPMMIntegration with the official DVM."

View File

@@ -0,0 +1,141 @@
#!/usr/bin/env bash
# Deployments — Chain 138 and multichain (nothing optional nor future; these are planned deployments).
# Usage:
# ./scripts/deployment/deploy-optional-future-all.sh # run all phases
# ./scripts/deployment/deploy-optional-future-all.sh --dry-run # print only
# ./scripts/deployment/deploy-optional-future-all.sh --phases 1,3,5 # run phases 1,3,5
#
# Requires: .env with PRIVATE_KEY, RPC_URL_138. Chain 138: --with-gas-price (default 2 gwei).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
if [ -f .env ]; then
set -a
source .env
set +a
fi
RPC="${RPC_URL_138:-http://192.168.11.211:8545}"
# Default 2 gwei to reduce "Replacement transaction underpriced"; override with GAS_PRICE_138.
GAS_PRICE="${GAS_PRICE_138:-2000000000}"
DRY_RUN=""
PHASES="" # comma-separated, e.g. 1,3,5
while [ $# -gt 0 ]; do
case "$1" in
--dry-run) DRY_RUN=1 ;;
--phases)
shift
[ $# -gt 0 ] && PHASES="$1"
;;
esac
shift
done
if [ -z "${PRIVATE_KEY:-}" ]; then
echo "ERROR: PRIVATE_KEY not set in .env"
exit 1
fi
# run_phase num name skip_var cmd [required_var]
# If required_var is set and skip_var is not set, requires that required_var is non-empty in env; else skips with message.
run_phase() {
local num="$1"
local name="$2"
local skip_var="$3"
local cmd="$4"
local required_var="${5:-}"
if [ -n "$PHASES" ]; then
if ! echo ",$PHASES," | grep -q ",$num,"; then
return 0
fi
fi
if [ -n "$skip_var" ]; then
local val=""
eval "val=\"\${${skip_var}:-}\""
if [ -n "$val" ]; then
echo "[Phase $num] $name — SKIP (${skip_var} already set)"
return 0
fi
fi
if [ -n "$required_var" ]; then
local req_val=""
eval "req_val=\"\${${required_var}:-}\""
if [ -z "$req_val" ]; then
echo "[Phase $num] $name — SKIP (set ${required_var} in .env to run; or set ${skip_var} to skip)"
return 0
fi
fi
echo "[Phase $num] $name — RUNNING"
if [ -n "$DRY_RUN" ]; then
echo " would run: $(echo "$cmd" | sed 's/--private-key "[^"]*"/--private-key ***REDACTED***/g')"
return 0
fi
eval "$cmd" || { echo "Phase $num failed."; exit 1; }
echo "[Phase $num] $name — DONE"
}
echo "============================================"
echo "Deployments — Chain 138 and multichain"
echo "RPC: $RPC"
echo "Gas price: $GAS_PRICE wei"
echo "============================================"
echo ""
# Phase 1: CREATE2 / Deterministic core
run_phase 1 "Deterministic core (DeployDeterministicCore)" "CREATE2_FACTORY" \
"forge script script/deploy/DeployDeterministicCore.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 2: Vault system
run_phase 2 "Vault system (DeployVaultSystem)" "VAULT_FACTORY" \
"forge script script/deploy/vault/DeployVaultSystem.s.sol:DeployVaultSystem --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 3: Reserve system (requires TOKEN_FACTORY)
run_phase 3 "Reserve system (DeployReserveSystem)" "RESERVE_SYSTEM" \
"forge script script/reserve/DeployReserveSystem.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 4: Reserve Keeper (requires ORACLE_PRICE_FEED unless RESERVE_KEEPER already set)
run_phase 4 "Reserve Keeper (DeployKeeper)" "RESERVE_KEEPER" \
"forge script script/reserve/DeployKeeper.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" \
"ORACLE_PRICE_FEED"
# Phase 5: PaymentChannelManager + GenericStateChannelManager
run_phase 5a "PaymentChannelManager" "PAYMENT_CHANNEL_MANAGER" \
"forge script script/DeployPaymentChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
run_phase 5b "GenericStateChannelManager" "GENERIC_STATE_CHANNEL_MANAGER" \
"forge script script/DeployGenericStateChannelManager.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 6: Trustless bridge (Lockbox138 on Chain 138)
run_phase 6 "Trustless bridge (Lockbox138)" "LOCKBOX_138" \
"forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 7: DODO / Swap (requires DODO_VENDING_MACHINE_ADDRESS, COMPLIANT_USDT_ADDRESS, COMPLIANT_USDC_ADDRESS)
run_phase 7 "DODO PMM Integration" "DODOPMM_INTEGRATION_ADDRESS" \
"forge script script/dex/DeployDODOPMMIntegration.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\"" \
"DODO_VENDING_MACHINE_ADDRESS"
# Phase 8: eMoney (Chain 138)
run_phase 8 "eMoney (DeployChain138)" "TOKEN_FACTORY_138" \
"forge script script/emoney/DeployChain138.s.sol:DeployChain138 --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
# Phase 9: Smart accounts (informational — actual deploy from ERC-4337 impl)
run_phase 9 "Smart accounts kit (informational)" "" \
"forge script script/smart-accounts/DeploySmartAccountsKit.s.sol --rpc-url \"$RPC\" --broadcast --private-key \"$PRIVATE_KEY\" --with-gas-price \"$GAS_PRICE\""
echo ""
echo "============================================"
echo "Deployments finished."
echo "Update .env with new addresses."
echo "DeployAll (mainnet/multichain): run script/DeployAll.s.sol per chain."
echo "Trustless bridge Mainnet: run DeployTrustlessBridge with MAINNET_RPC."
echo "See docs/03-deployment/OPTIONAL_FUTURE_DEPLOYMENTS_RUNBOOK.md"
echo "============================================"

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Deploy DODOPMMIntegration on each L2 (BSC, Polygon, Base, Optimism, Arbitrum, Avalanche, Cronos, Gnosis).
# Uses .env for RPC and token addresses. Chains via tag: --chain bsc polygon ... (or DEPLOY_PMM_L2S_FILTER in .env).
# Usage: ./scripts/deployment/deploy-pmm-all-l2s.sh [--chain bsc polygon base]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
parse_chain_filter "$@"
if [[ ${#CHAIN_FILTER[@]} -eq 0 && -n "${DEPLOY_PMM_L2S_FILTER:-}" ]]; then
CHAIN_FILTER=()
for n in $DEPLOY_PMM_L2S_FILTER; do n="$(normalize_chain_name "$n")"; [[ -n "$n" ]] && CHAIN_FILTER+=("$n"); done
fi
CHAINS=(
"BSC:56:BSC_RPC_URL"
"POLYGON:137:POLYGON_MAINNET_RPC"
"BASE:8453:BASE_MAINNET_RPC"
"OPTIMISM:10:OPTIMISM_MAINNET_RPC"
"ARBITRUM:42161:ARBITRUM_MAINNET_RPC"
"AVALANCHE:43114:AVALANCHE_RPC_URL"
"CRONOS:25:CRONOS_RPC_URL"
"GNOSIS:100:GNOSIS_MAINNET_RPC"
)
for entry in "${CHAINS[@]}"; do
IFS=: read -r name chain_id rpc_var <<< "$entry"
if [[ ${#CHAIN_FILTER[@]} -gt 0 ]] && [[ ! " ${CHAIN_FILTER[*]} " =~ " $name " ]]; then continue; fi
rpc="${!rpc_var:-}"
if [[ -z "$rpc" ]]; then
echo "Skip $name (chain $chain_id): $rpc_var not set"
continue
fi
# Prefer chain-prefixed DVM and tokens; fallback to global
dvm_var="${name}_DODO_VENDING_MACHINE_ADDRESS"
usdt_var="${name}_OFFICIAL_USDT_ADDRESS"
usdc_var="${name}_OFFICIAL_USDC_ADDRESS"
cusdt_var="${name}_COMPLIANT_USDT_ADDRESS"
cusdc_var="${name}_COMPLIANT_USDC_ADDRESS"
# Per-chain cUSDT/cUSDC (optional): CUSDT_ADDRESS_<chainId> / CUSDC_ADDRESS_<chainId> or POLYGON_COMPLIANT_USDT_ADDRESS etc.
cusdt_chain="CUSDT_ADDRESS_${chain_id}"
cusdc_chain="CUSDC_ADDRESS_${chain_id}"
dvm="${!dvm_var:-$DODO_VENDING_MACHINE_ADDRESS}"
usdt="${!usdt_var:-$OFFICIAL_USDT_ADDRESS}"
usdc="${!usdc_var:-$OFFICIAL_USDC_ADDRESS}"
compliant_usdt="${!cusdt_var:-${!cusdt_chain:-$usdt}}"
compliant_usdc="${!cusdc_var:-${!cusdc_chain:-$usdc}}"
if [[ -z "$dvm" ]] || [[ -z "$usdt" ]] || [[ -z "$usdc" ]]; then
echo "Skip $name: set ${dvm_var} (or DODO_VENDING_MACHINE_ADDRESS), ${usdt_var}, ${usdc_var} (or OFFICIAL_USDT/USDC_ADDRESS)"
continue
fi
echo "=== Deploying DODOPMMIntegration on $name (chain $chain_id) ==="
DODO_VENDING_MACHINE_ADDRESS="$dvm" \
OFFICIAL_USDT_ADDRESS="$usdt" \
OFFICIAL_USDC_ADDRESS="$usdc" \
COMPLIANT_USDT_ADDRESS="$compliant_usdt" \
COMPLIANT_USDC_ADDRESS="$compliant_usdc" \
forge script script/dex/DeployDODOPMMIntegration.s.sol:DeployDODOPMMIntegration \
--rpc-url "$rpc" \
--chain-id "$chain_id" \
--broadcast \
--private-key "$PRIVATE_KEY" \
-vvv || true
echo ""
done
echo "Done. Update .env with any new DODOPMM_INTEGRATION_<CHAIN> addresses."

View File

@@ -0,0 +1,85 @@
#!/usr/bin/env bash
# Deploy to chains with sufficient native token balance (Avalanche, Arbitrum, Cronos).
# Run check-balances-gas-and-deploy.sh first to confirm balances.
# Chain 138 phased core is deployed separately (check-balances-gas-and-deploy.sh --deploy).
#
# Requires: PRIVATE_KEY, CCIP_*_ROUTER, CCIP_*_LINK_TOKEN, *_SELECTOR, *_RPC_URL per chain.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
# Load .env
if [ -f .env ]; then
set -a
source .env
set +a
fi
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
NC='\033[0m'
if [ -z "${PRIVATE_KEY:-}" ]; then
echo -e "${RED}ERROR: PRIVATE_KEY not set in .env${NC}"
exit 1
fi
# Chains with sufficient balance (from last balance check): Avalanche, Arbitrum, Cronos
# Prefer INFURA_PROJECT_ID (+ optional INFURA_PROJECT_SECRET) when set; else public RPCs
[[ -f "$SCRIPT_DIR/../lib/infura.sh" ]] && source "$SCRIPT_DIR/../lib/infura.sh"
_av_rpc=$(build_infura_rpc "avalanche-mainnet" 2>/dev/null || true)
_ar_rpc=$(build_infura_rpc "arbitrum-mainnet" 2>/dev/null || true)
AVALANCHE_RPC="${AVALANCHE_RPC_URL:-${AVALANCHE_RPC:-${_av_rpc:-https://avalanche-c-chain.publicnode.com}}}"
ARBITRUM_RPC="${ARBITRUM_MAINNET_RPC:-${ARBITRUM_RPC:-${_ar_rpc:-https://arbitrum-one.publicnode.com}}}"
CRONOS_RPC="${CRONOS_RPC_URL:-${CRONOS_RPC:-https://evm.cronos.org}}"
deploy_chain() {
local name="$1"
local rpc="$2"
local chain_id="$3"
echo -e "${YELLOW}Deploying to ${name} (chain ${chain_id})...${NC}"
forge script script/DeployAll.s.sol:DeployAll \
--rpc-url "$rpc" \
--chain-id "$chain_id" \
--private-key "$PRIVATE_KEY" \
--broadcast \
--slow \
-vvvv || {
echo -e "${RED}${name} deployment failed${NC}"
return 1
}
echo -e "${GREEN}${name} deployment complete${NC}"
echo ""
}
echo -e "${BLUE}========================================${NC}"
echo -e "${BLUE}Deploy to chains with sufficient balance${NC}"
echo -e "${BLUE}========================================${NC}"
echo "Chains: Avalanche, Arbitrum, Cronos"
echo ""
# Verify required CCIP env vars
for chain in AVALANCHE ARBITRUM CRONOS; do
router="CCIP_${chain}_ROUTER"
link="CCIP_${chain}_LINK_TOKEN"
selector="${chain}_SELECTOR"
if [ -z "${!router:-}" ] || [ -z "${!link:-}" ] || [ -z "${!selector:-}" ]; then
echo -e "${RED}ERROR: Missing ${router}, ${link}, or ${selector} in .env${NC}"
exit 1
fi
done
# Deploy (skip --verify to avoid needing chain-specific explorer API keys)
deploy_chain "Avalanche" "$AVALANCHE_RPC" "43114"
deploy_chain "Arbitrum" "$ARBITRUM_RPC" "42161"
deploy_chain "Cronos" "$CRONOS_RPC" "25"
echo -e "${GREEN}========================================${NC}"
echo -e "${GREEN}Deployments complete${NC}"
echo -e "${GREEN}========================================${NC}"
echo "Next: update .env with deployed addresses; run verify manually if needed."

View File

@@ -0,0 +1,340 @@
#!/usr/bin/env bash
# Deploy WETH9/WETH10 + CCIP bridges (and optionally Cronos D-WIN W) to all blockchains
# unless a canonical/pre-existing deployment is already present in .env.
#
# Deploys:
# - WETH9, WETH10, CCIPWETH9Bridge, CCIPWETH10Bridge (via DeployAll.s.sol) on each chain
# where WETH9_<CHAIN> and WETH10_<CHAIN> are not both set.
# - On Cronos (25): optionally ISO-4217 W system (USDW, EURW, ...) if not already deployed.
# - With --deploy-c: cUSDT/cUSDC (and optional c*) on each chain where CUSDT_<CHAIN>/CUSDC_<CHAIN> unset (via DeployCompliantFiatTokensForChain.s.sol).
# - With --deploy-cw: cWUSDT/cWUSDC on each chain where CWUSDT_<CHAIN> unset (via DeployCWTokens.s.sol; set CW_BRIDGE_ADDRESS or CW_BRIDGE_<CHAIN>).
# - Chain 651940 (ALL Mainnet): env validation only (check AUSDT_ADDRESS_651940 set); no token deploy from this repo.
#
# Skips:
# - Ethereum Mainnet (1): uses canonical WETH from .env (WETH9_MAINNET, WETH10_MAINNET).
# - Any chain where both WETH9_* and WETH10_* are already set in .env.
# - Chain 138: not in DeployAll; compliant tokens (c*) are deployed separately on 138.
#
# Usage:
# cd smom-dbis-138 && ./scripts/deployment/deploy-tokens-and-weth-all-chains-skip-canonical.sh [OPTIONS]
#
# Options:
# --dry-run Print commands only; do not broadcast.
# --chain 25 56 137 Deploy only to these chain IDs (default: all supported).
# --no-iso4217 Do not deploy ISO-4217 W system on Cronos even if missing.
# --iso4217-only Only run Cronos ISO-4217 W deploy (skip DeployAll).
# --deploy-c Deploy cUSDT/cUSDC (and optional c*) on chains where CUSDT_<CHAIN>/CUSDC_<CHAIN> unset (skip 138, 1).
# --deploy-cw Deploy cWUSDT/cWUSDC on chains where CWUSDT_<CHAIN> unset; requires CW_BRIDGE_ADDRESS or CW_BRIDGE_<CHAIN> in .env.
#
# Requires: .env with PRIVATE_KEY; per-chain RPC and CCIP vars for chains you deploy to.
# See: docs/11-references/TOKENS_DEPLOYER_DEPLOYED_ON_OTHER_CHAINS.md
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
[ -f .env ] && set -a && source .env && set +a
DRY_RUN=false
CHAINS_FILTER=""
NO_ISO4217=false
ISO4217_ONLY=false
DEPLOY_C=false
DEPLOY_CW=false
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=true; shift ;;
--no-iso4217) NO_ISO4217=true; shift ;;
--iso4217-only) ISO4217_ONLY=true; shift ;;
--deploy-c) DEPLOY_C=true; shift ;;
--deploy-cw) DEPLOY_CW=true; shift ;;
--chain)
shift
CHAINS_FILTER="$*"
break
;;
*) shift ;;
esac
done
# Chain ID : Name : RPC env var (primary)
# DeployAll.s.sol supports: 1, 25, 56, 137, 100, 43114, 8453, 42161, 10. 651940 = env validation only.
ALL_CHAINS="1:Mainnet:ETH_MAINNET_RPC_URL 25:Cronos:CRONOS_RPC_URL 56:BSC:BSC_RPC_URL 137:Polygon:POLYGON_RPC_URL 100:Gnosis:GNOSIS_RPC_URL 43114:Avalanche:AVALANCHE_RPC_URL 8453:Base:BASE_RPC_URL 42161:Arbitrum:ARBITRUM_RPC_URL 10:Optimism:OPTIMISM_RPC_URL 651940:ALL:CHAIN_651940_RPC"
# Fallback RPC env names (some scripts use different names)
fallback_rpc() {
local chain_id="$1"
local rpc_var="$2"
local rpc="${!rpc_var:-}"
if [[ -z "$rpc" ]]; then
case "$chain_id" in
1) rpc="${ETHEREUM_MAINNET_RPC:-${ETH_MAINNET_RPC_URL:-}}";;
25) rpc="${CRONOS_RPC:-}";;
56) rpc="${BSC_RPC_URL:-}";;
137) rpc="${POLYGON_MAINNET_RPC:-}";;
100) rpc="${GNOSIS_RPC:-}";;
43114) rpc="${AVALANCHE_RPC_URL:-}";;
8453) rpc="${BASE_MAINNET_RPC:-}";;
42161) rpc="${ARBITRUM_MAINNET_RPC:-}";;
10) rpc="${OPTIMISM_MAINNET_RPC:-}";;
651940) rpc="${CHAIN_651940_RPC:-${ALL_MAINNET_RPC:-}}";;
esac
fi
echo "$rpc"
}
is_canonical_present() {
local weth9_var="$1"
local weth10_var="$2"
local w9="${!weth9_var:-}"
local w10="${!weth10_var:-}"
w9="${w9//0x/}"
w10="${w10//0x/}"
[[ -n "$w9" && "${#w9}" -ge 40 && "$w9" != "0000000000000000000000000000000000000000" ]] && \
[[ -n "$w10" && "${#w10}" -ge 40 && "$w10" != "0000000000000000000000000000000000000000" ]] && return 0
return 1
}
run_cmd() {
if $DRY_RUN; then
echo " [DRY-RUN] $*"
else
eval "$@" || return 1
fi
}
# ---------- DeployAll (WETH9, WETH10, CCIP bridges) per chain ----------
run_deploy_all() {
local chain_id="$1"
local name="$2"
local rpc_var="$3"
if [[ "$chain_id" == "651940" ]]; then
echo " Skip $name (chain 651940): DeployAll not supported; env validation only."
return 0
fi
local rpc
rpc=$(fallback_rpc "$chain_id" "$rpc_var")
if [[ -z "$rpc" ]]; then
echo " Skip $name (chain $chain_id): RPC not set ($rpc_var)."
return 0
fi
local weth9_var="WETH9_MAINNET" weth10_var="WETH10_MAINNET"
case "$chain_id" in
1) weth9_var="WETH9_MAINNET"; weth10_var="WETH10_MAINNET" ;;
25) weth9_var="WETH9_CRONOS"; weth10_var="WETH10_CRONOS" ;;
56) weth9_var="WETH9_BSC"; weth10_var="WETH10_BSC" ;;
137) weth9_var="WETH9_POLYGON"; weth10_var="WETH10_POLYGON" ;;
100) weth9_var="WETH9_GNOSIS"; weth10_var="WETH10_GNOSIS" ;;
43114) weth9_var="WETH9_AVALANCHE"; weth10_var="WETH10_AVALANCHE" ;;
8453) weth9_var="WETH9_BASE"; weth10_var="WETH10_BASE" ;;
42161) weth9_var="WETH9_ARBITRUM"; weth10_var="WETH10_ARBITRUM" ;;
10) weth9_var="WETH9_OPTIMISM"; weth10_var="WETH10_OPTIMISM" ;;
*) echo " Unsupported chain ID $chain_id"; return 1 ;;
esac
# Mainnet: use canonical WETH from .env; DeployAll only deploys CCIPLogger (placeholder). Skip to avoid requiring env.
if [[ "$chain_id" == "1" ]]; then
if is_canonical_present "$weth9_var" "$weth10_var"; then
echo " Skip $name (chain $chain_id): canonical WETH9/WETH10 already set."
return 0
fi
echo " Skip $name (chain $chain_id): set WETH9_MAINNET and WETH10_MAINNET in .env for canonical WETH; DeployAll on Mainnet does not deploy tokens."
return 0
fi
if is_canonical_present "$weth9_var" "$weth10_var"; then
echo " Skip $name (chain $chain_id): WETH9/WETH10 already set in .env."
return 0
fi
echo " Deploying WETH9, WETH10, CCIP bridges on $name (chain $chain_id)..."
local gas_opts="--legacy"
run_cmd "forge script script/DeployAll.s.sol:DeployAll --rpc-url \"$rpc\" --chain-id \"$chain_id\" --broadcast --private-key \"\$PRIVATE_KEY\" $gas_opts -vvv" || true
echo " → Set WETH9_${name^^}, WETH10_${name^^}, CCIPWETH9_BRIDGE_${name^^}, CCIPWETH10_BRIDGE_${name^^} in .env from script output."
}
# ---------- ISO-4217 W (Cronos): deploy only if USDW not already deployed ----------
run_iso4217_cronos() {
if $NO_ISO4217; then
echo " Skip Cronos ISO-4217 W (--no-iso4217)."
return 0
fi
local rpc
rpc=$(fallback_rpc 25 "CRONOS_RPC_URL")
[[ -z "$rpc" ]] && rpc="${CRONOS_RPC:-}"
if [[ -z "$rpc" ]]; then
echo " Skip Cronos ISO-4217 W: CRONOS_RPC_URL / CRONOS_RPC not set."
return 0
fi
local usdw_addr="0x948690147D2e50ffe50C5d38C14125aD6a9FA036"
local code_len
code_len=$(cast code "$usdw_addr" --rpc-url "$rpc" 2>/dev/null | wc -c)
if [[ -n "$code_len" && "$code_len" -gt 10 ]]; then
echo " Skip Cronos ISO-4217 W: USDW already deployed at $usdw_addr."
return 0
fi
echo " Deploying ISO-4217 W system on Cronos (25)..."
run_cmd "forge script script/deploy/iso4217w/DeployISO4217WSystem.s.sol:DeployISO4217WSystem --rpc-url \"$rpc\" --chain-id 25 --broadcast --private-key \"\$PRIVATE_KEY\" --legacy -vvv" || true
echo " → Record MintController, TokenRegistry, USDW, EURW, ... addresses from output; add to .env / docs."
}
# ---------- c* (cUSDT, cUSDC) on other chains: DeployCompliantFiatTokensForChain ----------
run_deploy_c() {
local chain_id="$1"
local name="$2"
local rpc_var="$3"
[[ "$chain_id" == "138" || "$chain_id" == "1" ]] && return 0
local rpc
rpc=$(fallback_rpc "$chain_id" "$rpc_var")
if [[ -z "$rpc" ]]; then return 0; fi
local cusdt_var="CUSDT_${name^^}" cusdc_var="CUSDC_${name^^}"
local cusdt_val="${!cusdt_var:-}" cusdc_val="${!cusdc_var:-}"
cusdt_val="${cusdt_val//0x/}"; cusdc_val="${cusdc_val//0x/}"
if [[ -n "$cusdt_val" && "${#cusdt_val}" -ge 40 ]] && [[ -n "$cusdc_val" && "${#cusdc_val}" -ge 40 ]]; then
echo " Skip c* on $name (chain $chain_id): CUSDT_${name^^} and CUSDC_${name^^} already set."
return 0
fi
echo " Deploying cUSDT/cUSDC on $name (chain $chain_id)..."
run_cmd "forge script script/deploy/DeployCompliantFiatTokensForChain.s.sol:DeployCompliantFiatTokensForChain --rpc-url \"$rpc\" --chain-id \"$chain_id\" --broadcast --private-key \"\$PRIVATE_KEY\" --legacy -vvv" || true
echo " → Set CUSDT_${name^^}, CUSDC_${name^^} in .env from script output."
}
# ---------- cW* (all 12: cWUSDT, cWUSDC, cWEURC, cWEURT, cWGBPC, cWGBPT, cWAUDC, cWJPYC, cWCHFC, cWCADC, cWXAUC, cWXAUT): DeployCWTokens ----------
run_deploy_cw() {
local chain_id="$1"
local name="$2"
local rpc_var="$3"
local rpc
rpc=$(fallback_rpc "$chain_id" "$rpc_var")
if [[ -z "$rpc" ]]; then return 0; fi
local bridge_var="CW_BRIDGE_${name^^}"
local bridge="${!bridge_var:-${CW_BRIDGE_ADDRESS:-}}"
if [[ -z "$bridge" || "$bridge" == "0x"*"0000000000000000000000000000000000000000" ]]; then
echo " Skip cW* on $name (chain $chain_id): set CW_BRIDGE_ADDRESS or CW_BRIDGE_${name^^} in .env."
return 0
fi
local cw_var="CWUSDT_${name^^}"
local cw_val="${!cw_var:-}"
cw_val="${cw_val//0x/}"
local deploy_opts=""
if [[ -n "$cw_val" && "${#cw_val}" -ge 40 ]]; then
echo " Deploying remaining cW* (cWEURC..cWXAUT) on $name (chain $chain_id) (bridge $bridge)..."
deploy_opts="DEPLOY_CWUSDT=0 DEPLOY_CWUSDC=0"
else
echo " Deploying all cW* (12 tokens) on $name (chain $chain_id) (bridge $bridge)..."
fi
local gas_opt=""
[[ "$chain_id" == "42161" && -n "${ARBITRUM_GAS_PRICE:-}" ]] && gas_opt="--with-gas-price ${ARBITRUM_GAS_PRICE}"
run_cmd "${deploy_opts:+$deploy_opts }CW_BRIDGE_ADDRESS=$bridge forge script script/deploy/DeployCWTokens.s.sol:DeployCWTokens --rpc-url \"$rpc\" --chain-id \"$chain_id\" --broadcast --private-key \"\$PRIVATE_KEY\" --legacy ${gas_opt} -vvv" || true
echo " → Set CWUSDT_*, CWUSDC_*, CWEURC_*, CWEURT_*, CWGBPC_*, CWGBPT_*, CWAUDC_*, CWJPYC_*, CWCHFC_*, CWCADC_*, CWXAUC_*, CWXAUT_* in .env from script output."
}
# ---------- 651940 (ALL Mainnet): env validation only ----------
run_651940_validate() {
local rpc
rpc=$(fallback_rpc 651940 "CHAIN_651940_RPC")
if [[ -z "$rpc" ]]; then
echo " Skip ALL (651940): CHAIN_651940_RPC not set."
return 0
fi
local ausdt_var="AUSDT_ADDRESS_651940"
local ausdt_val="${!ausdt_var:-}"
if [[ -z "$ausdt_val" || "$ausdt_val" == "0x0000000000000000000000000000000000000000" ]]; then
echo " ALL (651940): Set AUSDT_ADDRESS_651940 in .env (ecosystem token; not deployed by this script)."
else
echo " ALL (651940): AUSDT_ADDRESS_651940 set."
fi
}
# ---------- Main ----------
echo "=============================================="
echo "Deploy tokens/WETH to all chains (skip canonical)"
echo "=============================================="
echo " Dry-run: $DRY_RUN"
echo " Chain filter: ${CHAINS_FILTER:-all}"
echo " ISO-4217 on Cronos: $(! $NO_ISO4217 && ! $ISO4217_ONLY || $ISO4217_ONLY)"
echo " Deploy c* (cUSDT/cUSDC): $DEPLOY_C"
echo " Deploy cW* (cWUSDT/cWUSDC): $DEPLOY_CW"
echo ""
if [[ -z "${PRIVATE_KEY:-}" ]]; then
echo "ERROR: PRIVATE_KEY not set in .env." >&2
exit 1
fi
if ! $ISO4217_ONLY; then
echo "--- DeployAll (WETH9, WETH10, CCIP bridges) per chain ---"
for entry in $ALL_CHAINS; do
chain_id="${entry%%:*}"; rest="${entry#*:}"
name="${rest%%:*}"; rpc_var="${rest#*:}"
if [[ -n "$CHAINS_FILTER" ]]; then
echo "$CHAINS_FILTER" | grep -q "\b$chain_id\b" || continue
fi
run_deploy_all "$chain_id" "$name" "$rpc_var"
done
echo ""
fi
if ! $ISO4217_ONLY; then
if [[ -z "$CHAINS_FILTER" ]] || echo "$CHAINS_FILTER" | grep -q "\b25\b"; then
echo "--- Cronos: ISO-4217 W (USDW, EURW, ...) ---"
run_iso4217_cronos
echo ""
fi
else
echo "--- Cronos: ISO-4217 W only ---"
run_iso4217_cronos
echo ""
fi
if $DEPLOY_C; then
echo "--- Deploy c* (cUSDT/cUSDC) per chain (skip 138, 1) ---"
for entry in $ALL_CHAINS; do
chain_id="${entry%%:*}"; rest="${entry#*:}"
name="${rest%%:*}"; rpc_var="${rest#*:}"
if [[ "$chain_id" == "651940" ]]; then continue; fi
if [[ -n "$CHAINS_FILTER" ]]; then
echo "$CHAINS_FILTER" | grep -q "\b$chain_id\b" || continue
fi
run_deploy_c "$chain_id" "$name" "$rpc_var"
done
echo ""
fi
if $DEPLOY_CW; then
echo "--- Deploy cW* (cWUSDT/cWUSDC) per chain ---"
for entry in $ALL_CHAINS; do
chain_id="${entry%%:*}"; rest="${entry#*:}"
name="${rest%%:*}"; rpc_var="${rest#*:}"
if [[ "$chain_id" == "651940" ]]; then continue; fi
if [[ -n "$CHAINS_FILTER" ]]; then
echo "$CHAINS_FILTER" | grep -q "\b$chain_id\b" || continue
fi
run_deploy_cw "$chain_id" "$name" "$rpc_var"
done
echo ""
fi
echo "--- Chain 651940 (ALL Mainnet) env validation ---"
for entry in $ALL_CHAINS; do
chain_id="${entry%%:*}"; rest="${entry#*:}"
name="${rest%%:*}"; rpc_var="${rest#*:}"
if [[ "$chain_id" != "651940" ]]; then continue; fi
if [[ -n "$CHAINS_FILTER" ]]; then
echo "$CHAINS_FILTER" | grep -q "\b651940\b" || continue
fi
run_651940_validate
break
done
echo ""
echo "=============================================="
echo "Done. Update .env with deployed addresses; see TOKENS_DEPLOYER_DEPLOYED_ON_OTHER_CHAINS.md."
echo "=============================================="

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env bash
# Deploy Trustless Bridge stack (BondManager, ChallengeManager, LiquidityPool, Inbox, optional Lockbox) on each L2.
# Uses .env for RPC and PRIVATE_KEY. Chains via --chain bsc polygon ...; Lockbox via --lockbox / --no-lockbox (not .env).
#
# Usage:
# ./scripts/deployment/deploy-trustless-l2s.sh
# ./scripts/deployment/deploy-trustless-l2s.sh --chain bsc polygon --lockbox
# ./scripts/deployment/deploy-trustless-l2s.sh --no-lockbox
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
DOTENV="$REPO_ROOT/.env"
cd "$REPO_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
parse_lockbox_tag "$@"
set -- "${PARSE_LOCKBOX_REMAINING[@]}"
parse_chain_filter "$@"
# Backward compat: single positional chain (e.g. deploy-trustless-l2s.sh BSC)
if [[ ${#CHAIN_FILTER[@]} -eq 0 && ${#PARSE_CHAIN_FILTER_REMAINING[@]} -eq 1 ]]; then
n="$(normalize_chain_name "${PARSE_CHAIN_FILTER_REMAINING[0]}")"
[[ -n "$n" ]] && CHAIN_FILTER=("$n")
fi
get_rpc() { local n="$1"; case "$n" in BSC) echo "${BSC_RPC_URL:-}";; POLYGON) echo "${POLYGON_MAINNET_RPC:-}";; BASE) echo "${BASE_MAINNET_RPC:-}";; OPTIMISM) echo "${OPTIMISM_MAINNET_RPC:-}";; ARBITRUM) echo "${ARBITRUM_MAINNET_RPC:-}";; AVALANCHE) echo "${AVALANCHE_RPC_URL:-}";; CRONOS) echo "${CRONOS_RPC_URL:-}";; GNOSIS) echo "${GNOSIS_MAINNET_RPC:-}";; *) echo "";; esac; }
get_weth() { local n="$1"; local v="${n}_WETH_ADDRESS"; if [[ -n "${!v:-}" ]]; then echo "${!v}"; return; fi; case "$n" in BSC) echo "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c";; POLYGON) echo "0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270";; BASE) echo "0x4200000000000000000000000000000000000006";; OPTIMISM) echo "0x4200000000000000000000000000000000000006";; ARBITRUM) echo "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1";; AVALANCHE) echo "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7";; CRONOS) echo "0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23";; GNOSIS) echo "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d";; *) echo "";; esac; }
get_chain_id() { case "$1" in BSC) echo 56;; POLYGON) echo 137;; BASE) echo 8453;; OPTIMISM) echo 10;; ARBITRUM) echo 42161;; AVALANCHE) echo 43114;; CRONOS) echo 25;; GNOSIS) echo 100;; *) echo 0;; esac; }
for name in BSC POLYGON BASE OPTIMISM ARBITRUM AVALANCHE CRONOS GNOSIS; do
if [[ ${#CHAIN_FILTER[@]} -gt 0 ]] && [[ ! " ${CHAIN_FILTER[*]} " =~ " $name " ]]; then continue; fi
rpc="$(get_rpc "$name")"
if [[ -z "$rpc" ]]; then echo "Skip $name: RPC not set"; continue; fi
weth="$(get_weth "$name")"
chain_id="$(get_chain_id "$name")"
echo "=== Deploying Trustless stack on $name (chain $chain_id) ==="
TRUSTLESS_WETH_ADDRESS="$weth" TRUSTLESS_DEPLOY_LOCKBOX="${TRUSTLESS_DEPLOY_LOCKBOX:-0}" \
forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \
--rpc-url "$rpc" --chain-id "$chain_id" --broadcast --private-key "$PRIVATE_KEY" --slow -vvv || true
echo ""
done
echo "Done. Update .env with BondManager, ChallengeManager, LiquidityPool, Inbox (and Lockbox) per chain."

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# Deploy Vault System, then ac* / vdc* / sdc* vaults (DeployAcVdcSdcVaults).
# Run from a host that can reach Chain 138 RPC (e.g. on same LAN as 192.168.11.211).
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source .env 2>/dev/null || true
RPC_URL="${RPC_URL_138:-http://192.168.11.211:8545}"
GAS_PRICE="${GAS_PRICE:-1000000000}"
CHAIN_ID="${CHAIN_ID:-138}"
if [ -z "$PRIVATE_KEY" ]; then
echo "Error: PRIVATE_KEY not set (e.g. in smom-dbis-138/.env)"
exit 1
fi
if [[ ! "$PRIVATE_KEY" =~ ^0x ]]; then
export PRIVATE_KEY="0x$PRIVATE_KEY"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "1. Deploy Vault System (DeployVaultSystem.s.sol)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "RPC: $RPC_URL Chain: $CHAIN_ID Gas: $GAS_PRICE"
echo ""
forge script script/deploy/vault/DeployVaultSystem.s.sol:DeployVaultSystem \
--rpc-url "$RPC_URL" \
--broadcast \
--with-gas-price "$GAS_PRICE"
# Resolve VaultFactory address from broadcast (last contract creation)
RUN_JSON=""
for candidate in \
"broadcast/DeployVaultSystem.s.sol/$CHAIN_ID/run-latest.json" \
"broadcast/vault/DeployVaultSystem.s.sol/$CHAIN_ID/run-latest.json" \
"broadcast/script/deploy/vault/DeployVaultSystem.s.sol/$CHAIN_ID/run-latest.json"; do
if [ -f "$candidate" ]; then
RUN_JSON="$candidate"
break
fi
done
if [ -z "$RUN_JSON" ] || [ ! -f "$RUN_JSON" ]; then
echo "Could not find broadcast file. Set VAULT_FACTORY_ADDRESS manually and run:"
echo " VAULT_FACTORY_ADDRESS=0x... forge script script/deploy/vault/DeployAcVdcSdcVaults.s.sol:DeployAcVdcSdcVaults --rpc-url \$RPC_URL_138 --broadcast --with-gas-price 1000000000"
exit 1
fi
VAULT_FACTORY_ADDRESS=$(jq -r '[.transactions[] | select(.contractAddress != null) | .contractAddress] | last' "$RUN_JSON")
if [ -z "$VAULT_FACTORY_ADDRESS" ] || [ "$VAULT_FACTORY_ADDRESS" = "null" ]; then
echo "Could not parse Vault Factory address from $RUN_JSON. Set VAULT_FACTORY_ADDRESS and run DeployAcVdcSdcVaults manually."
exit 1
fi
export VAULT_FACTORY_ADDRESS
echo ""
echo "Vault Factory address: $VAULT_FACTORY_ADDRESS"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "2. Deploy ac* / vdc* / sdc* (DeployAcVdcSdcVaults.s.sol)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Optional: set CUSDC_ADDRESS_138, CUSDT_ADDRESS_138 (or COMPLIANT_USDC_ADDRESS, COMPLIANT_USDT_ADDRESS) to create vaults for those tokens."
echo ""
forge script script/deploy/vault/DeployAcVdcSdcVaults.s.sol:DeployAcVdcSdcVaults \
--rpc-url "$RPC_URL" \
--broadcast \
--with-gas-price "$GAS_PRICE"
echo ""
echo "Done. Record Vault Factory and any new vault/deposit/debt token addresses in .env and config/smart-contracts-master.json if needed."

View File

@@ -0,0 +1,83 @@
#!/usr/bin/env bash
# Ensure prerequisites for: LINK funding, PMM (Chain 138), CCIPLogger deploy.
# Run from repo root (proxmox) or smom-dbis-138. Fixes what can be automated and reports the rest.
# Usage: ./scripts/deployment/ensure-prerequisites.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# PROJECT_ROOT = smom-dbis-138
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
ok() { echo -e "${GREEN}${NC} $1"; }
warn() { echo -e "${YELLOW}${NC} $1"; }
fail() { echo -e "${RED}${NC} $1"; }
echo "=== Prerequisites (LINK funding, PMM, CCIPLogger) ==="
echo ""
# 1) .env
if [[ ! -f "$PROJECT_ROOT/.env" ]]; then
fail ".env not found in $PROJECT_ROOT"
exit 1
fi
ok ".env exists"
set -a
source "$PROJECT_ROOT/.env" 2>/dev/null || true
set +a
[[ -z "${PRIVATE_KEY:-}" ]] && fail "PRIVATE_KEY not set in .env" || ok "PRIVATE_KEY set"
[[ -z "${RPC_URL_138:-}" ]] && warn "RPC_URL_138 not set" || ok "RPC_URL_138 set"
# 2) npm install in smom-dbis-138 (for Hardhat / CCIPLogger)
echo ""
echo "--- Dependencies (CCIPLogger / Hardhat) ---"
if [[ -f "$PROJECT_ROOT/package.json" ]]; then
if [[ ! -d "$PROJECT_ROOT/node_modules/hardhat" ]]; then
warn "Hardhat not found in node_modules. Running: npm install --legacy-peer-deps"
npm install --legacy-peer-deps 2>/dev/null || true
fi
if [[ -d "$PROJECT_ROOT/node_modules/hardhat" ]]; then
ok "Hardhat available (node_modules)"
else
warn "Hardhat still missing; run from $PROJECT_ROOT: npm install --legacy-peer-deps"
fi
else
warn "No package.json in $PROJECT_ROOT"
fi
# 3) LINK funding prereqs
echo ""
echo "--- LINK funding ---"
[[ -z "${LINK_TOKEN_CHAIN138:-${LINK_TOKEN:-}}" ]] && warn "LINK_TOKEN_CHAIN138/LINK_TOKEN not set" || ok "Chain 138 LINK token set"
[[ -z "${CCIPWETH9_BRIDGE_CHAIN138:-}" ]] && warn "CCIPWETH9_BRIDGE_CHAIN138 not set" || ok "CCIPWETH9_BRIDGE_CHAIN138 set"
[[ -z "${MAINNET_CCIP_WETH9_BRIDGE:-}" ]] && warn "MAINNET_CCIP_WETH9_BRIDGE not set" || ok "Mainnet bridge vars set"
echo " Deployer must have LINK on each chain. Run: scripts/deployment/fund-ccip-bridges-with-link.sh (use DRY_RUN=1 first)."
# 4) PMM prereqs
echo ""
echo "--- PMM (Chain 138) ---"
if [[ -z "${DODO_VENDING_MACHINE_ADDRESS:-}" || "${DODO_VENDING_MACHINE_ADDRESS}" =~ ^0x?0*$ ]]; then
warn "DODO_VENDING_MACHINE_ADDRESS not set. Set to DODO DVM factory on Chain 138 to run PMM (see docs/deployment/ALL_MAINNETS_DEPLOYMENT_RUNBOOK.md)."
else
ok "DODO_VENDING_MACHINE_ADDRESS set"
fi
[[ -z "${COMPLIANT_USDT_ADDRESS:-}" ]] && warn "COMPLIANT_USDT_ADDRESS not set" || ok "COMPLIANT_USDT_ADDRESS set"
[[ -z "${COMPLIANT_USDC_ADDRESS:-}" ]] && warn "COMPLIANT_USDC_ADDRESS not set" || ok "COMPLIANT_USDC_ADDRESS set"
[[ -z "${OFFICIAL_USDT_ADDRESS:-}" ]] && warn "OFFICIAL_USDT_ADDRESS not set" || ok "OFFICIAL_USDT_ADDRESS set"
[[ -z "${OFFICIAL_USDC_ADDRESS:-}" ]] && warn "OFFICIAL_USDC_ADDRESS not set" || ok "OFFICIAL_USDC_ADDRESS set"
echo " Then run: scripts/deployment/run-pmm-and-pools.sh"
# 5) CCIPLogger
echo ""
echo "--- CCIPLogger ---"
echo " Optional. From $PROJECT_ROOT run: scripts/deployment/deploy-ccip-logger-all-chains.sh"
echo " If Hardhat compile fails (e.g. missing @emoney/interfaces), fix deps or skip CCIPLogger."
echo ""
echo "=== Done. Address any ⚠ items above, then run the task scripts. ==="

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# Export flattened Solidity source for Cronos manual verification.
# Paste each file at https://explorer.cronos.org/verifyContract
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
OUT_DIR="$PROJECT_ROOT/.cronos-verify"
cd "$PROJECT_ROOT"
mkdir -p "$OUT_DIR"
CONTRACTS=(
"contracts/tokens/WETH.sol:WETH"
"contracts/tokens/WETH10.sol:WETH10"
"contracts/ccip/CCIPWETH9Bridge.sol:CCIPWETH9Bridge"
"contracts/ccip/CCIPWETH10Bridge.sol:CCIPWETH10Bridge"
)
ADDRESSES=(
"0x99B3511A2d315A497C8112C1fdd8D508d4B1E506"
"0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6"
"0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e"
"0x105F8A15b819948a89153505762444Ee9f324684"
)
echo "Exporting flattened source for Cronos manual verification..."
echo ""
for i in "${!CONTRACTS[@]}"; do
entry="${CONTRACTS[$i]}"
addr="${ADDRESSES[$i]}"
path="${entry%%:*}"
name="${entry##*:}"
base=$(basename "$path" .sol)
out="$OUT_DIR/${base}_flattened.sol"
forge flatten "$path" > "$out" 2>/dev/null
echo "$name -> $out"
done
# Export Standard JSON Input (required — includes viaIR:true)
echo "Exporting Standard JSON Input (includes viaIR — required for bytecode match)..."
forge verify-contract "${ADDRESSES[0]}" "${CONTRACTS[0]}" --chain cronos --show-standard-json-input 2>/dev/null | jq -c . > "$OUT_DIR/WETH_standard_input.json"
forge verify-contract "${ADDRESSES[1]}" "${CONTRACTS[1]}" --chain cronos --show-standard-json-input 2>/dev/null | jq -c . > "$OUT_DIR/WETH10_standard_input.json"
forge verify-contract "${ADDRESSES[2]}" "${CONTRACTS[2]}" --chain cronos --constructor-args "$(cast abi-encode 'constructor(address,address,address)' 0xE26B0A098D861d5C7d9434aD471c0572Ca6EAa67 0x99B3511A2d315A497C8112C1fdd8D508d4B1E506 0x8c80A01F461f297Df7F9DA3A4f740D7297C8Ac85)" --show-standard-json-input 2>/dev/null | jq -c . > "$OUT_DIR/CCIPWETH9Bridge_standard_input.json"
forge verify-contract "${ADDRESSES[3]}" "${CONTRACTS[3]}" --chain cronos --constructor-args "$(cast abi-encode 'constructor(address,address,address)' 0xE26B0A098D861d5C7d9434aD471c0572Ca6EAa67 0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6 0x8c80A01F461f297Df7F9DA3A4f740D7297C8Ac85)" --show-standard-json-input 2>/dev/null | jq -c . > "$OUT_DIR/CCIPWETH10Bridge_standard_input.json"
echo " ✓ Standard JSON files written to $OUT_DIR/*_standard_input.json"
echo ""
echo "IMPORTANT: Use Standard-Json-Input (not flattened source). Contracts were deployed with via_ir=true."
echo " Flattened source produces different bytecode → Unmatched."
echo ""
echo "Next: https://explorer.cronos.org/verifyContract"
echo " 1. Select 'Solidity (Standard-Json-Input)'"
echo " 2. Upload the *_standard_input.json file for each contract"
echo " 3. See docs/deployment/CRONOS_VERIFICATION_RUNBOOK.md"
echo ""
echo "Sources: $OUT_DIR/"

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Fix nonce mismatch by clearing broadcast/cache so Forge uses fresh on-chain nonce.
# Usage: ./scripts/deployment/fix-nonce-and-retry.sh [--chain cronos] [--script <path>]
# ./scripts/deployment/fix-nonce-and-retry.sh cronos # positional still supported
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
load_deployment_env
CHAIN=""
SCRIPT=""
while [[ $# -gt 0 ]]; do
case "$1" in
--chain) CHAIN="${2:-cronos}"; shift 2 ;;
--script) SCRIPT="${2:-script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge}"; shift 2 ;;
*) if [[ -z "$CHAIN" ]]; then CHAIN="$1"; elif [[ -z "$SCRIPT" ]]; then SCRIPT="$1"; fi; shift ;;
esac
done
CHAIN="${CHAIN:-cronos}"
SCRIPT="${SCRIPT:-script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge}"
case "$(echo "$CHAIN" | tr '[:upper:]' '[:lower:]')" in
cronos) RPC="${CRONOS_RPC_URL:-https://evm.cronos.org}"; CHAIN_ID=25 ;;
chain138) RPC="${RPC_URL_138:-${CHAIN_138_RPC_URL:-}}"; CHAIN_ID=138 ;;
bsc) RPC="${BSC_RPC_URL:-}"; CHAIN_ID=56 ;;
polygon) RPC="${POLYGON_MAINNET_RPC:-}"; CHAIN_ID=137 ;;
base) RPC="${BASE_MAINNET_RPC:-}"; CHAIN_ID=8453 ;;
optimism) RPC="${OPTIMISM_MAINNET_RPC:-}"; CHAIN_ID=10 ;;
arbitrum) RPC="${ARBITRUM_MAINNET_RPC:-}"; CHAIN_ID=42161 ;;
avalanche) RPC="${AVALANCHE_RPC_URL:-}"; CHAIN_ID=43114 ;;
gnosis) RPC="${GNOSIS_MAINNET_RPC:-}"; CHAIN_ID=100 ;;
*) echo "Unknown chain: $CHAIN (use: cronos, chain138, bsc, polygon, base, optimism, arbitrum, avalanche, gnosis)"; exit 1 ;;
esac
if [[ -z "$RPC" ]]; then echo "RPC not set for $CHAIN"; exit 1; fi
DEPLOYER=$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null || true)
NONCE=$(cast nonce "$DEPLOYER" --rpc-url "$RPC" 2>/dev/null || echo "0")
echo "Deployer: $DEPLOYER"
echo "Current on-chain nonce: $NONCE"
echo "RPC: $RPC"
echo ""
# Clear broadcast cache so Forge fetches fresh nonce
CACHE_DIR="$PROJECT_ROOT/cache"
BROADCAST_DIR="$PROJECT_ROOT/broadcast"
SCRIPT_PATH="${SCRIPT%%:*}"
rm -rf "$CACHE_DIR/$SCRIPT_PATH/$CHAIN_ID" 2>/dev/null || true
rm -rf "$BROADCAST_DIR/$SCRIPT_PATH/$CHAIN_ID" 2>/dev/null || true
echo "Cleared cache for $SCRIPT_PATH on chain $CHAIN_ID"
echo ""
echo "Run deployment (use --slow to avoid nonce gaps):"
echo " forge script $SCRIPT --rpc-url \"$RPC\" --chain-id $CHAIN_ID --broadcast --private-key \"\$PRIVATE_KEY\" --slow"
echo ""

View File

@@ -0,0 +1,91 @@
#!/usr/bin/env bash
# Fund all CCIP WETH9/WETH10 bridge contracts with LINK on each chain.
# Amount via tag (not .env): --link <amount> (default 10 LINK), --dry-run to print commands only.
# Usage: ./scripts/deployment/fund-ccip-bridges-with-link.sh [--link 10] [--dry-run]
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
parse_link_tags "$@"
[[ -f "$SCRIPT_DIR/../lib/infura.sh" ]] && source "$SCRIPT_DIR/../lib/infura.sh" 2>/dev/null || true
[[ -n "${PRIVATE_KEY:-}" && ! "$PRIVATE_KEY" =~ ^0x ]] && PRIVATE_KEY="0x$PRIVATE_KEY"
run_or_echo() {
if [[ "${DRY_RUN:-0}" = "1" ]]; then
echo " [DRY RUN] $*"
else
if eval "$*"; then
echo " OK"
else
echo " Failed (non-fatal)"
fi
fi
}
ensure_rpc() { local rpc="$1"; type ensure_infura_rpc_url &>/dev/null && [[ -n "$rpc" ]] && rpc=$(ensure_infura_rpc_url "$rpc"); echo "$rpc"; }
if [[ -z "$PRIVATE_KEY" ]]; then
echo "ERROR: PRIVATE_KEY not set" >&2
exit 1
fi
echo "Funding CCIP bridges with LINK (amount per bridge: $LINK_AMOUNT_WEI wei)"
echo ""
# Chain 138
if [[ -n "${RPC_URL_138:-}" && -n "${LINK_TOKEN_CHAIN138:-${LINK_TOKEN:-}}" ]]; then
link="${LINK_TOKEN_CHAIN138:-$LINK_TOKEN}"
rpc=$(ensure_rpc "$RPC_URL_138")
echo "Chain 138 (RPC: ${rpc%%\?*}...)"
[[ -n "${CCIPWETH9_BRIDGE_CHAIN138:-}" ]] && run_or_echo "cast send $link \"transfer(address,uint256)\" $CCIPWETH9_BRIDGE_CHAIN138 $LINK_AMOUNT_WEI --rpc-url \"$rpc\" --private-key \"\$PRIVATE_KEY\" --legacy"
[[ -n "${CCIPWETH10_BRIDGE_CHAIN138:-}" ]] && run_or_echo "cast send $link \"transfer(address,uint256)\" $CCIPWETH10_BRIDGE_CHAIN138 $LINK_AMOUNT_WEI --rpc-url \"$rpc\" --private-key \"\$PRIVATE_KEY\" --legacy"
echo ""
fi
# Ethereum
if [[ -n "${ETHEREUM_MAINNET_RPC:-}" && -n "${MAINNET_LINK_TOKEN:-${CCIP_ETH_LINK_TOKEN:-}}" ]]; then
link="${MAINNET_LINK_TOKEN:-$CCIP_ETH_LINK_TOKEN}"
rpc=$(ensure_rpc "$ETHEREUM_MAINNET_RPC")
echo "Ethereum Mainnet"
[[ -n "${MAINNET_CCIP_WETH9_BRIDGE:-}" ]] && run_or_echo "cast send $link \"transfer(address,uint256)\" $MAINNET_CCIP_WETH9_BRIDGE $LINK_AMOUNT_WEI --rpc-url \"$rpc\" --private-key \"\$PRIVATE_KEY\" --legacy"
[[ -n "${MAINNET_CCIP_WETH10_BRIDGE:-}" ]] && run_or_echo "cast send $link \"transfer(address,uint256)\" $MAINNET_CCIP_WETH10_BRIDGE $LINK_AMOUNT_WEI --rpc-url \"$rpc\" --private-key \"\$PRIVATE_KEY\" --legacy"
echo ""
fi
# BSC, Polygon, Base, Optimism, Arbitrum, Avalanche, Cronos, Gnosis, Celo
for label in BSC POLYGON BASE OPTIMISM ARBITRUM AVALANCHE CRONOS GNOSIS CELO; do
case "$label" in
BSC) rpc_var="BSC_RPC_URL"; link_var="CCIP_BSC_LINK_TOKEN"; ;;
POLYGON) rpc_var="POLYGON_MAINNET_RPC"; link_var="CCIP_POLYGON_LINK_TOKEN"; ;;
BASE) rpc_var="BASE_MAINNET_RPC"; link_var="CCIP_BASE_LINK_TOKEN"; ;;
OPTIMISM) rpc_var="OPTIMISM_MAINNET_RPC"; link_var="CCIP_OPTIMISM_LINK_TOKEN"; ;;
ARBITRUM) rpc_var="ARBITRUM_MAINNET_RPC"; link_var="CCIP_ARBITRUM_LINK_TOKEN"; ;;
AVALANCHE) rpc_var="AVALANCHE_RPC_URL"; link_var="CCIP_AVALANCHE_LINK_TOKEN"; ;;
CRONOS) rpc_var="CRONOS_RPC_URL"; link_var="CCIP_CRONOS_LINK_TOKEN"; rpc_fb="CRONOS_RPC"; link_fb="LINK_TOKEN_CRONOS"; ;;
GNOSIS) rpc_var="GNOSIS_MAINNET_RPC"; link_var="CCIP_GNOSIS_LINK_TOKEN"; rpc_fb="GNOSIS_RPC"; link_fb="LINK_TOKEN_GNOSIS"; ;;
CELO) rpc_var="CELO_MAINNET_RPC"; link_var="CCIP_CELO_LINK_TOKEN"; rpc_fb="CELO_RPC"; link_fb="LINK_TOKEN_CELO"; ;;
esac
rpc="${!rpc_var:-${!rpc_fb:-}}"
link="${!link_var:-${!link_fb:-}}"
rpc=$(ensure_rpc "$rpc")
[[ -z "$rpc" || -z "$link" ]] && continue
bridge9_var="CCIPWETH9_BRIDGE_${label}"
bridge10_var="CCIPWETH10_BRIDGE_${label}"
addr9="${!bridge9_var:-}"
addr10="${!bridge10_var:-}"
[[ -z "$addr9" && -z "$addr10" ]] && continue
echo "$label"
[[ -n "$addr9" ]] && run_or_echo "cast send $link \"transfer(address,uint256)\" $addr9 $LINK_AMOUNT_WEI --rpc-url \"$rpc\" --private-key \"\$PRIVATE_KEY\" --legacy"
[[ -n "$addr10" ]] && run_or_echo "cast send $link \"transfer(address,uint256)\" $addr10 $LINK_AMOUNT_WEI --rpc-url \"$rpc\" --private-key \"\$PRIVATE_KEY\" --legacy"
echo ""
done
echo "Done. Use --link <amount> and --dry-run to adjust."

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Fund the mainnet LiquidityPoolETH with ETH and/or WETH (G4).
# Uses .env for PRIVATE_KEY, LIQUIDITY_POOL_ETH_MAINNET (or LIQUIDITY_POOL), ETHEREUM_MAINNET_RPC.
# Amounts via tags (not .env): --eth <amount>, --weth <amount> (in ETH), or --eth-wei / --weth-wei.
# If no amounts given and stdin is a TTY, prompts interactively.
#
# Usage:
# ./scripts/deployment/fund-mainnet-lp.sh --eth 1.5 --weth 0.5
# ./scripts/deployment/fund-mainnet-lp.sh --eth 1
# ./scripts/deployment/fund-mainnet-lp.sh # interactive prompt
# ./scripts/deployment/fund-mainnet-lp.sh --dry-run # no tx, show what would be sent
#
# Callable from other scripts: pass same tags; or source and call run_fund_mainnet_lp "${args[@]}"
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
# Load deployment env and tag parsing
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
# Parse tags; remaining args left in PARSE_FUND_TAGS_REMAINING
parse_fund_tags "$@"
# Interactive if no amounts and TTY
prompt_fund_amounts
if [[ "${FUND_ETH_AMOUNT_WEI:-0}" == "0" && "${FUND_WETH_AMOUNT_WEI:-0}" == "0" ]]; then
echo "No amounts set. Use --eth <amount> and/or --weth <amount>, or run interactively."
echo "Example: $0 --eth 1.5 --weth 0.5"
exit 0
fi
require_fund_lp_env || exit 1
if [[ "${DRY_RUN:-0}" == "1" ]]; then
echo "Dry run: would fund LP with ETH wei=$FUND_ETH_AMOUNT_WEI, WETH wei=$FUND_WETH_AMOUNT_WEI"
exit 0
fi
echo "Funding mainnet LP at $LIQUIDITY_POOL_ETH_MAINNET (ETH wei=$FUND_ETH_AMOUNT_WEI, WETH wei=$FUND_WETH_AMOUNT_WEI)"
FUND_ETH_AMOUNT_WEI="$FUND_ETH_AMOUNT_WEI" FUND_WETH_AMOUNT_WEI="$FUND_WETH_AMOUNT_WEI" \
forge script script/bridge/trustless/FundMainnetLP.s.sol:FundMainnetLP \
--rpc-url "$ETHEREUM_MAINNET_RPC" \
--broadcast \
--private-key "$PRIVATE_KEY" \
-vvv

View File

@@ -0,0 +1,140 @@
#!/bin/bash
# Generate all chain adapters and deployment configurations
# This script creates the complete multi-chain integration package
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
CONTRACTS_DIR="$PROJECT_ROOT/contracts/bridge/adapters"
SCRIPTS_DIR="$PROJECT_ROOT/script/deploy/chains"
CONFIG_DIR="$PROJECT_ROOT/config/chains"
echo "🚀 Generating comprehensive multi-chain adapter deployment package..."
# Create directory structure
mkdir -p "$CONTRACTS_DIR"/{evm,non-evm,hyperledger}
mkdir -p "$SCRIPTS_DIR"/{evm,non-evm,hyperledger}
mkdir -p "$CONFIG_DIR"/{evm,non-evm,hyperledger}
mkdir -p "$PROJECT_ROOT/services"/{firefly-bridge,cacti-bridge,fabric-bridge,indy-verifier}
mkdir -p "$PROJECT_ROOT/docs/chains"/{evm,non-evm,hyperledger}
echo "✅ Directory structure created"
# Generate chain configuration files
cat > "$CONFIG_DIR/SUPPORTED_CHAINS.md" << 'EOF'
# Supported Chains - Complete List
## EVM Chains
| Chain | Chain ID | Status | Adapter | Explorer |
|-------|----------|--------|---------|----------|
| ChainID 138 | 138 | ✅ Live | UniversalCCIPBridge | https://explorer.d-bis.org |
| Ethereum Mainnet | 1 | ⚠️ Deploy | EVMAdapter | https://etherscan.io |
| Polygon | 137 | ⚠️ Deploy | EVMAdapter | https://polygonscan.com |
| Arbitrum | 42161 | ⚠️ Deploy | EVMAdapter | https://arbiscan.io |
| Optimism | 10 | ⚠️ Deploy | EVMAdapter | https://optimistic.etherscan.io |
| Base | 8453 | ⚠️ Deploy | EVMAdapter | https://basescan.org |
| Avalanche | 43114 | ⚠️ Deploy | EVMAdapter | https://snowtrace.io |
| BSC | 56 | ⚠️ Deploy | EVMAdapter | https://bscscan.com |
| XDC Network | 50 | ⚠️ Deploy | XDCAdapter | https://explorer.xdc.network |
| ALL Mainnet | 651940 | ⚠️ Deploy | AlltraAdapter | https://alltra.global |
## Non-EVM Chains
| Chain | Type | Status | Adapter | Explorer |
|-------|------|--------|---------|----------|
| XRP Ledger | XRPL | ⚠️ Deploy | XRPLAdapter | https://xrpscan.com |
| Stellar | Stellar | 🔨 Plan | StellarAdapter | https://stellarchain.io |
| Algorand | Algorand | 🔨 Plan | AlgorandAdapter | https://algoexplorer.io |
| Hedera | Hashgraph | 🔨 Plan | HederaAdapter | https://hashscan.io |
| Tron | Tron | 🔨 Plan | TronAdapter | https://tronscan.org |
| TON | TON | 🔨 Plan | TONAdapter | https://tonscan.org |
| Cosmos Hub | Cosmos | 🔨 Plan | CosmosAdapter | https://mintscan.io |
| Solana | Solana | 🔨 Plan | SolanaAdapter | https://solscan.io |
## Hyperledger Enterprise
| Framework | Type | Status | Adapter | Nodes |
|-----------|------|--------|---------|-------|
| Firefly | Orchestration | ✅ Deployed | FireflyAdapter | VMID 6202, 6203 |
| Cacti | Interoperability | ✅ Deployed | CactiAdapter | VMID 5201 |
| Fabric | Permissioned | 🔨 Plan | FabricAdapter | TBD |
| Indy | Identity | 🔨 Plan | IndyVerifier | TBD |
## Legend
- ✅ Live: Fully deployed and operational
- ⚠️ Deploy: Code ready, needs deployment
- 🔨 Plan: Design phase, implementation needed
EOF
echo "✅ Chain configuration documentation created"
# Create deployment orchestrator script
cat > "$PROJECT_ROOT/scripts/deployment/deploy-all-chains.sh" << 'EOF'
#!/bin/bash
# Deploy Universal Bridge to all supported chains
# This script orchestrates deployment across all chains
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
source "$PROJECT_ROOT/.env" 2>/dev/null || true
# Chain configurations
declare -A EVM_CHAINS=(
["1"]="Ethereum Mainnet"
["137"]="Polygon"
["42161"]="Arbitrum"
["10"]="Optimism"
["8453"]="Base"
["43114"]="Avalanche"
["56"]="BSC"
["50"]="XDC Network"
)
# Deployment function
deploy_chain() {
local chain_id=$1
local chain_name=$2
echo "📦 Deploying to $chain_name (Chain ID: $chain_id)..."
# Run deployment script for this chain
if [ -f "$PROJECT_ROOT/script/deploy/chains/evm/deploy-chain-$chain_id.s.sol" ]; then
forge script "script/deploy/chains/evm/deploy-chain-$chain_id.s.sol:DeployChain" \
--rpc-url "${RPC_URLS[$chain_id]}" \
--broadcast \
--private-key "$PRIVATE_KEY" \
--verify || echo "⚠️ Deployment failed for $chain_name"
else
echo "⚠️ Deployment script not found for $chain_name"
fi
}
# Main deployment loop
echo "🚀 Starting multi-chain deployment..."
echo ""
for chain_id in "${!EVM_CHAINS[@]}"; do
deploy_chain "$chain_id" "${EVM_CHAINS[$chain_id]}"
echo ""
done
echo "✅ Multi-chain deployment complete!"
EOF
chmod +x "$PROJECT_ROOT/scripts/deployment/deploy-all-chains.sh"
echo "✅ Deployment orchestrator script created"
echo ""
echo "🎉 Multi-chain adapter generation complete!"
echo ""
echo "Next steps:"
echo "1. Review generated adapters in: $CONTRACTS_DIR"
echo "2. Configure chain RPC endpoints in: $CONFIG_DIR"
echo "3. Run deployment: ./scripts/deployment/deploy-all-chains.sh"
echo "4. Configure admin dashboard with new chains"

View File

@@ -0,0 +1,236 @@
#!/usr/bin/env bash
# List all tokens in the deployer wallet across all networks.
# Token categories (see docs/11-references/TOKEN_CATEGORIES_CANONICAL.md):
# 1. Canonical 138 Compliant: Native ETH, WETH, WETH10, LINK, cUSDT, cUSDC, cEURT, cEURC, cGBPT, cGBPC, cAUDT, cAUDC, cJPYT, cJPYC, cCHFT, cCHFC, cCADT, cCADC, cAUSDT
# 2. ALL Mainnet (Alltra): Native, AUSDT, USDT, USDC, WETH, WALL
# 3. Compliant Wrapped (cW*): cWUSDT, cWUSDC, cWEURT, cWEURC, ... (per public chain)
# 4. D-WIN W Tokens: USDW, EURW, GBPW, AUDW, JPYW, CHFW, CADW (Cronos §4)
# This script lists (1) Chain 138, (2) ALL Mainnet, (4) Cronos D-WIN W, plus Ethereum/Polygon/Base/Optimism/BSC/Avalanche/Arbitrum.
# Uses PRIVATE_KEY or DEPLOYER_ADDRESS; falls back to public RPCs when env RPC vars unset.
#
# Usage: ./scripts/deployment/list-deployer-tokens-all-networks.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
if [ -f .env ]; then
set -a
source .env
set +a
fi
# Deployer: derive from PRIVATE_KEY or use DEPLOYER_ADDRESS if set (read-only mode)
if [ -n "${DEPLOYER_ADDRESS:-}" ]; then
DEPLOYER="${DEPLOYER_ADDRESS}"
[[ "$DEPLOYER" != 0x* ]] && DEPLOYER="0x$DEPLOYER"
else
if [ -z "${PRIVATE_KEY:-}" ]; then
echo "ERROR: Set PRIVATE_KEY in .env or DEPLOYER_ADDRESS=0x4A666F96fC8764181194447A7dFdb7d471b301C8 for read-only"
exit 1
fi
DEPLOYER=$(cast wallet address "$PRIVATE_KEY" 2>/dev/null || true)
if [ -z "$DEPLOYER" ]; then
echo "ERROR: Could not derive deployer address (is 'cast' available?)"
exit 1
fi
fi
# Format raw balance with decimals (divide by 10^decimals). Uses cast when decimals=18.
format_balance() {
local raw="$1"
local decimals="${2:-18}"
if [ -z "$raw" ] || [ "$raw" = "0" ]; then
echo "0"
return
fi
if [ "$decimals" = "18" ]; then
cast --to-unit "$raw" ether 2>/dev/null || echo "$raw"
return
fi
# bc: 10^decimals (e.g. 10^6 for USDC)
echo "scale=12; $raw / 10^$decimals" | bc 2>/dev/null | sed 's/^\./0./;s/0*$//;s/\.$//' || echo "$raw"
}
# Fetch ERC-20 balance and decimals, print " SYMBOL: balance"
token_balance_line() {
local rpc="$1"
local token_addr="$2"
local symbol="$3"
local decimals_override="${4:-}"
local bal_hex
bal_hex=$(cast call "$token_addr" "balanceOf(address)(uint256)" "$DEPLOYER" --rpc-url "$rpc" 2>/dev/null || echo "0x0")
local bal_raw
bal_raw=$(cast --to-dec "$bal_hex" 2>/dev/null || echo "0")
if [ -z "$decimals_override" ]; then
decimals_override=$(cast call "$token_addr" "decimals()(uint8)" --rpc-url "$rpc" 2>/dev/null | cast --to-dec 2>/dev/null || echo "18")
fi
local disp
disp=$(format_balance "$bal_raw" "$decimals_override")
printf " %-8s %s\n" "$symbol:" "$disp"
}
# Report one network: native + optional ERC-20 list (name, rpc, chain_id, native_symbol, "addr:symbol:decimals ...")
report_network() {
local name="$1"
local rpc="$2"
local chain_id="$3"
local native_sym="$4"
local token_list="$5"
echo ""
echo "=== $name (chain $chain_id) ==="
if [ -z "$rpc" ]; then
echo " (no RPC configured)"
return
fi
local native_wei
native_wei=$(cast balance "$DEPLOYER" --rpc-url "$rpc" 2>/dev/null || echo "0")
local native_disp
native_disp=$(cast --to-unit "$native_wei" ether 2>/dev/null || echo "0")
echo " Native ($native_sym): $native_disp"
local entry addr rest sym dec
for entry in $token_list; do
entry=$(echo "$entry" | tr -d '[:space:]')
[ -z "$entry" ] && continue
addr="${entry%%:*}"
rest="${entry#*:}"
sym="${rest%%:*}"
dec="${rest#*:}"
[ "$dec" = "$rest" ] && dec=""
token_balance_line "$rpc" "$addr" "$sym" "$dec"
done
}
echo "============================================"
echo "Deployer wallet tokens (all networks)"
echo "Deployer: $DEPLOYER"
echo "============================================"
# Fallback public RPCs when env not set (so token lists are always shown)
RPC_138="${RPC_URL_138:-https://rpc-core.d-bis.org}"
RPC_1="${ETHEREUM_MAINNET_RPC:-https://eth.llamarpc.com}"
RPC_651940="${CHAIN_651940_RPC:-${ALLTRA_MAINNET_RPC:-https://mainnet-rpc.alltra.global}}"
RPC_25="${CRONOS_RPC:-${CRONOS_MAINNET_RPC:-https://evm.cronos.org}}"
RPC_137="${POLYGON_MAINNET_RPC:-https://polygon-rpc.com}"
RPC_8453="${BASE_MAINNET_RPC:-https://mainnet.base.org}"
RPC_10="${OPTIMISM_MAINNET_RPC:-https://mainnet.optimism.io}"
RPC_56="${BSC_RPC_URL:-${BSC_MAINNET_RPC:-https://bsc-dataseed.binance.org}}"
RPC_43114="${AVALANCHE_RPC_URL:-${AVALANCHE_MAINNET_RPC:-https://api.avax.network/ext/bc/C/rpc}}"
RPC_42161="${ARBITRUM_MAINNET_RPC:-https://arb1.arbitrum.io/rpc}"
# Chain 138 tokens (from CHAIN138_TOKEN_ADDRESSES)
CHAIN138_TOKENS="
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2:WETH:18
0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f:WETH10:18
0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03:LINK:18
0x93E66202A11B1772E55407B32B44e5Cd8eda7f22:cUSDT:6
0xf22258f57794CC8E06237084b353Ab30fFfa640b:cUSDC:6
0x15DF1D5BFDD8Aa4b380445D4e3E9B38d34283619:USDT:6
"
report_network "Chain 138" "$RPC_138" "138" "ETH" "$CHAIN138_TOKENS"
# Ethereum Mainnet
MAINNET_TOKENS="
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2:WETH:18
0xdAC17F958D2ee523a2206206994597C13D831ec7:USDT:6
0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48:USDC:6
0x514910771AF9Ca656af840dff83E8264EcF986CA:LINK:18
0x6B175474E89094C44Da98b954EedeAC495271d0F:DAI:18
"
report_network "Ethereum Mainnet" "$RPC_1" "1" "ETH" "$MAINNET_TOKENS"
# ALL Mainnet (651940)
ALLMAINNET_TOKENS="
0x015B1897Ed5279930bC2Be46F661894d219292A6:AUSDT:18
0x66D8Efa0AF63B0e84eb1Dd72bf00f00cd1e2234e:USDT:18
0xa95EeD79f84E6A0151eaEb9d441F9Ffd50e8e881:USDC:18
0x798F6762BB40d6801A593459d08F890603D3979C:WETH:18
0x2da2b8f961F161ab6320acB3377e2e844a3C3ce4:WALL:18
"
report_network "ALL Mainnet (Alltra)" "$RPC_651940" "651940" "ETH" "$ALLMAINNET_TOKENS"
# Cronos (25)
CRONOS_TOKENS="
0x99B3511A2d315A497C8112C1fdd8D508d4B1E506:WETH9:18
0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6:WETH10:18
0x8c80A01F461f297Df7F9DA3A4f740D7297C8Ac85:LINK:18
0x948690147D2e50ffe50C5d38C14125aD6a9FA036:USDW:2
0x58a8D8F78F1B65c06dAd7542eC46b299629A60dd:EURW:2
0xFb4B6Cc81211F7d886950158294A44C312abCA29:GBPW:2
0xf9f5D0ACD71C76F9476F10B3F3d3E201F0883C68:AUDW:2
0xeE17bB0322383fecCA2784fbE2d4CD7d02b1905B:JPYW:2
0xc9750828124D4c10e7a6f4B655cA8487bD3842EB:CHFW:2
0x328Cd365Bb35524297E68ED28c6fF2C9557d1363:CADW:2
"
report_network "Cronos" "$RPC_25" "25" "CRO" "$CRONOS_TOKENS"
# Polygon
POLYGON_TOKENS="
0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619:WETH:18
0xc2132D05D31c914a87C6611C10748AEb04B58e8F:USDT:6
0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174:USDC:6
0xb0897686c545045aFc77CF20eA7Ee945E98F291e:LINK:18
"
report_network "Polygon" "$RPC_137" "137" "MATIC" "$POLYGON_TOKENS"
# Base
BASE_TOKENS="
0x4200000000000000000000000000000000000006:WETH:18
0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913:USDC:6
0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb:DAI:18
"
report_network "Base" "$RPC_8453" "8453" "ETH" "$BASE_TOKENS"
# Optimism
OPTIMISM_TOKENS="
0x4200000000000000000000000000000000000006:WETH:18
0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85:USDC:6
0x94b008aA00579c1307B0EF2c499aD98a8ce58e58:USDT:6
"
report_network "Optimism" "$RPC_10" "10" "ETH" "$OPTIMISM_TOKENS"
# BSC (56)
BSC_TOKENS="
0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173c095c:WBNB:18
0x55d398326f99059fF775485246999027B3197955:USDT:18
0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d:USDC:18
0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c:BTCB:18
"
report_network "BSC (BNB Chain)" "$RPC_56" "56" "BNB" "$BSC_TOKENS"
# Avalanche C-Chain
AVAX_TOKENS="
0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7:WAVAX:18
0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7:USDT:6
0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E:USDC:6
"
report_network "Avalanche C-Chain" "$RPC_43114" "43114" "AVAX" "$AVAX_TOKENS"
# Arbitrum One
ARBITRUM_TOKENS="
0x82aF49447D8a07e3bd95BD0d56f35241523fBab1:WETH:18
0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9:USDT:6
0xaf88d065e77c8cC2239327C5EDb3A432268e5831:USDC:6
"
report_network "Arbitrum One" "$RPC_42161" "42161" "ETH" "$ARBITRUM_TOKENS"
# Sepolia (optional; no token list)
report_network "Ethereum Sepolia" "${ETHEREUM_SEPOLIA_RPC:-}" "11155111" "ETH" ""
# Polygon Amoy
report_network "Polygon Amoy" "${POLYGON_AMOY_RPC:-}" "80002" "MATIC" ""
# Base Sepolia
report_network "Base Sepolia" "${BASE_SEPOLIA_RPC:-}" "84532" "ETH" ""
# Optimism Sepolia
report_network "Optimism Sepolia" "${OPTIMISM_SEPOLIA_RPC:-}" "11155420" "ETH" ""
echo ""
echo "============================================"
echo "Done. Override RPCs via .env: RPC_URL_138, ETHEREUM_MAINNET_RPC, CHAIN_651940_RPC, CRONOS_RPC, etc."
echo "============================================"

View File

@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Print cast commands for live trustless bridge test (138 -> mainnet) and optionally check LP/BondManager state.
# Does NOT send the lock tx; you run that and capture depositId from the Deposit event.
# Usage: ./scripts/deployment/live-test-trustless-bridge.sh [--check]
# --check Print LP getPoolStats(0) and BondManager totalEthHeld() for mainnet.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
[[ -f .env ]] && set -a && source .env && set +a
BOND_MANAGER="${BOND_MANAGER_MAINNET:-${BOND_MANAGER:-}}"
CHALLENGE_MANAGER="${CHALLENGE_MANAGER_MAINNET:-${CHALLENGE_MANAGER:-}}"
LIQUIDITY_POOL="${LIQUIDITY_POOL_ETH_MAINNET:-${LIQUIDITY_POOL:-}}"
INBOX_ETH="${INBOX_ETH_MAINNET:-${INBOX_ETH:-}}"
RPC_138="${RPC_URL_138:-${CHAIN_138_RPC_URL:-}}"
RPC_MAINNET="${ETHEREUM_MAINNET_RPC:-}"
if [[ "${1:-}" == "--check" ]]; then
echo "--- Mainnet LP ETH pool stats (AssetType 0) ---"
cast call "$LIQUIDITY_POOL" "getPoolStats(uint8)(uint256,uint256,uint256)" 0 --rpc-url "$RPC_MAINNET" 2>/dev/null || echo " (set LIQUIDITY_POOL and ETHEREUM_MAINNET_RPC)"
echo "--- BondManager totalEthHeld ---"
cast call "$BOND_MANAGER" "totalEthHeld()(uint256)" --rpc-url "$RPC_MAINNET" 2>/dev/null || echo " (set BOND_MANAGER and ETHEREUM_MAINNET_RPC)"
echo ""
fi
echo "=== Live test commands (138 -> mainnet) ==="
echo "Set: RECIPIENT (mainnet address), DEPOSIT_ID (from Lockbox Deposit event depositId — NOT the amount), AMOUNT_WEI (e.g. 1000000000000000 for 0.001 ether)"
echo ""
echo "Get DEPOSIT_ID after lock: ./scripts/deployment/run-e2e-trustless-live-test.sh get-deposit-id <LOCK_TX_HASH> # or cast logs <TX> \"Deposit(...)\" --rpc-url \$RPC_URL_138"
echo ""
echo "1) Lock on Chain 138 (run this; then get DEPOSIT_ID from Deposit event):"
echo " cast send \$LOCKBOX_138 \"depositNative(address,bytes32)\" \$RECIPIENT \$(cast keccak \"live-test-\$(date +%s)\") --value 0.01ether --rpc-url \$RPC_URL_138 --private-key \$PRIVATE_KEY --legacy --gas-price \${GAS_PRICE_138:-1000000000}"
echo ""
echo "2) Bond for claim (run and set BOND=...):"
echo " BOND=\$(cast call \$BOND_MANAGER \"getRequiredBond(uint256)\" \$AMOUNT_WEI --rpc-url \$ETHEREUM_MAINNET_RPC)"
echo ""
echo "3) Submit claim on mainnet:"
echo " cast send \$INBOX_ETH \"submitClaim(uint256,address,uint256,address,bytes)\" \$DEPOSIT_ID 0x0000000000000000000000000000000000000000 \$AMOUNT_WEI \$RECIPIENT 0x --value \$BOND --rpc-url \$ETHEREUM_MAINNET_RPC --private-key \$PRIVATE_KEY"
echo ""
echo "4) After challenge window (e.g. 30 min), finalize:"
echo " cast send \$CHALLENGE_MANAGER \"finalizeClaim(uint256)\" \$DEPOSIT_ID --rpc-url \$ETHEREUM_MAINNET_RPC --private-key \$PRIVATE_KEY # CHALLENGE_MANAGER in .env"
echo ""
echo "5) Release bond:"
echo " cast send \$BOND_MANAGER \"releaseBond(uint256)\" \$DEPOSIT_ID --rpc-url \$ETHEREUM_MAINNET_RPC --private-key \$PRIVATE_KEY"
echo ""
echo "Full runbook: docs/bridge/trustless/DEPLOYMENT_GUIDE.md (Deploy, Configure, and Live Test section)"

View File

@@ -0,0 +1,145 @@
#!/usr/bin/env bash
# Preflight check for Config-Ready Chains (Gnosis, Cronos, Celo, Wemix) CCIP bridge deployment.
# Verifies: RPC connectivity, deployer address, native gas balance on each chain.
# Run before deploy-bridges-config-ready-chains.sh.
#
# Usage: ./scripts/deployment/preflight-config-ready-chains.sh [gnosis|cronos|celo|wemix|all]
# SKIP_BALANCE=1 ... # skip balance checks (RPC-only)
# DEPLOYER_ADDRESS=0x... # use specific address instead of deriving from PRIVATE_KEY
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
[[ -f "$PROJECT_ROOT/.env" ]] && set -a && source "$PROJECT_ROOT/.env" && set +a
SKIP_BALANCE="${SKIP_BALANCE:-0}"
CHAIN="${1:-all}"
# Chain config: name | chain_id | RPC_var | gas_token | min_recommended (human)
get_chain_config() {
case "$1" in
gnosis) echo "Gnosis|100|GNOSIS_RPC|xDAI|0.1" ;;
cronos) echo "Cronos|25|CRONOS_RPC|CRO|1" ;;
celo) echo "Celo|42220|CELO_RPC|CELO|0.1" ;;
wemix) echo "Wemix|1111|WEMIX_RPC|WEMIX|0.4" ;;
*) echo "" ;;
esac
}
# Default RPCs (from env or public)
GNOSIS_RPC="${GNOSIS_RPC:-https://rpc.gnosischain.com}"
CRONOS_RPC="${CRONOS_RPC:-https://evm.cronos.org}"
CELO_RPC="${CELO_RPC:-https://forno.celo.org}"
WEMIX_RPC="${WEMIX_RPC:-https://api.wemix.com}"
# Deployer
if [[ -n "${DEPLOYER_ADDRESS:-}" ]]; then
DEPLOYER="${DEPLOYER_ADDRESS}"
[[ "$DEPLOYER" != 0x* ]] && DEPLOYER="0x$DEPLOYER"
else
if [[ -z "${PRIVATE_KEY:-}" ]]; then
echo "Error: Set PRIVATE_KEY in .env or DEPLOYER_ADDRESS for read-only check" >&2
exit 1
fi
DEPLOYER=$(cast wallet address "$PRIVATE_KEY" 2>/dev/null || true)
if [[ -z "$DEPLOYER" ]]; then
echo "Error: Could not derive deployer from PRIVATE_KEY (is 'cast' available?)" >&2
exit 1
fi
fi
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
check_chain() {
local key="$1"
local config
config=$(get_chain_config "$key")
[[ -z "$config" ]] && return 1
local name chain_id rpc_var gas_token min_rec
IFS='|' read -r name chain_id rpc_var gas_token min_rec <<< "$config"
local rpc="${!rpc_var:-}"
if [[ -z "$rpc" ]]; then
echo -e " ${RED}${NC} $name: $rpc_var not set in .env"
return 1
fi
# RPC connectivity
local res
res=$(curl -s -m 10 -X POST "$rpc" -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' 2>/dev/null || true)
if [[ -z "$res" ]] || ! echo "$res" | grep -q '"result"'; then
echo -e " ${RED}${NC} $name: RPC unreachable ($rpc)"
return 1
fi
echo -e " ${GREEN}${NC} $name: RPC OK (chain $chain_id)"
if [[ "$SKIP_BALANCE" == "1" ]]; then
return 0
fi
# Balance check
local balance_wei
balance_wei=$(cast balance "$DEPLOYER" --rpc-url "$rpc" 2>/dev/null || echo "0")
local balance_eth
balance_eth=$(echo "scale=6; $balance_wei / 1000000000000000000" | bc 2>/dev/null || echo "0")
if [[ -z "$balance_wei" || "$balance_wei" == "0" ]]; then
echo -e " ${RED}${NC} Balance: 0 $gas_token (need $min_rec $gas_token)"
return 1
fi
# Compare: balance_eth >= min_rec (use bc for decimals)
if ! command -v bc >/dev/null 2>&1; then
echo -e " ${YELLOW}?${NC} Balance: $balance_eth $gas_token (bc not found, cannot compare)"
return 0
fi
if [[ "$(echo "$balance_eth >= $min_rec" | bc 2>/dev/null)" != "1" ]]; then
echo -e " ${YELLOW}${NC} Balance: $balance_eth $gas_token (recommended: $min_rec $gas_token)"
return 1
fi
echo -e " ${GREEN}${NC} Balance: $balance_eth $gas_token"
return 0
}
run_checks() {
local keys
case "$CHAIN" in
gnosis) keys="gnosis" ;;
cronos) keys="cronos" ;;
celo) keys="celo" ;;
wemix) keys="wemix" ;;
all) keys="gnosis cronos celo wemix" ;;
*) echo "Usage: $0 [gnosis|cronos|celo|wemix|all]"; exit 1 ;;
esac
local failed=0
for k in $keys; do
if ! check_chain "$k"; then
failed=1
fi
done
return $failed
}
echo "=== Preflight: Config-Ready Chains (Gnosis, Cronos, Celo, Wemix) ==="
echo "Deployer: ${DEPLOYER:0:10}...${DEPLOYER: -8}"
echo "SKIP_BALANCE=$SKIP_BALANCE CHAIN=$CHAIN"
echo ""
if run_checks; then
echo ""
echo "Preflight OK. Run: ./scripts/deployment/deploy-bridges-config-ready-chains.sh $CHAIN"
exit 0
else
echo ""
echo "Preflight failed. Fix RPCs and gas balances before deploy."
echo " Gas tokens: Gnosis=xDAI, Cronos=CRO, Celo=CELO, Wemix=WEMIX"
echo " Recommended: Gnosis 0.1, Cronos 1, Celo 0.1, Wemix 0.4"
exit 1
fi

View File

@@ -0,0 +1,64 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Script, console} from "forge-std/Script.sol";
import {ChainRegistry} from "../../contracts/registry/ChainRegistry.sol";
/**
* @title RegisterAllMainnet
* @notice Register ALL Mainnet (651940) in ChainRegistry
* @dev Run this after deploying AlltraAdapter
*/
contract RegisterAllMainnet is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);
// Load environment variables
address registryAddress = vm.envOr("CHAIN_REGISTRY_ADDRESS", address(0));
address alltraAdapterAddress = vm.envOr("ALLTRA_ADAPTER_ADDRESS", address(0));
require(registryAddress != address(0), "CHAIN_REGISTRY_ADDRESS not set");
require(alltraAdapterAddress != address(0), "ALLTRA_ADAPTER_ADDRESS not set");
console.log("Registering ALL Mainnet (651940) in ChainRegistry");
console.log("Registry:", vm.toString(registryAddress));
console.log("Adapter:", vm.toString(alltraAdapterAddress));
vm.startBroadcast(deployerPrivateKey);
ChainRegistry registry = ChainRegistry(registryAddress);
// Register ALL Mainnet as EVM chain
// Parameters:
// - chainId: 651940
// - adapter: AlltraAdapter address
// - explorerUrl: https://alltra.global
// - minConfirmations: 12 (standard EVM)
// - avgBlockTime: 2 seconds (TBD - verify actual block time)
// - additionalData: empty (can include CCIP selector if available later)
registry.registerEVMChain(
651940, // chainId
alltraAdapterAddress, // adapter
"https://alltra.global", // explorerUrl
12, // minConfirmations
2, // avgBlockTime (seconds) - TODO: Verify actual block time
"" // additionalData
);
vm.stopBroadcast();
console.log("\n=== Registration Summary ===");
console.log("Chain ID: 651940");
console.log("Chain Name: ALL Mainnet");
console.log("Adapter:", vm.toString(alltraAdapterAddress));
console.log("Explorer: https://alltra.global");
console.log("Min Confirmations: 12");
console.log("Avg Block Time: 2 seconds");
console.log("\n✅ ALL Mainnet registered successfully!");
console.log("\nNext Steps:");
console.log("1. Verify chain registration: cast call <REGISTRY> 'evmChains(uint256)(uint256,string,uint8,address,bool,uint256,uint256,bool,string,string,bytes)' 651940 --rpc-url <RPC>");
console.log("2. Test adapter: Verify AlltraAdapter.getChainIdentifier() returns (651940, 'ALL-Mainnet')");
console.log("3. Update routing services to use AlltraAdapter for chain 651940");
}
}

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# Run all deployment tasks in parallel where possible.
# Respects dependency order. Requires .env with PRIVATE_KEY, RPC URLs.
# Usage: ./scripts/deployment/run-all-deployments-parallel.sh [chain]
# chain: chain138 (default), cronos, mainnet
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source .env 2>/dev/null || true
CHAIN="${1:-chain138}"
case "$CHAIN" in
chain138) RPC="${RPC_URL_138:-$CHAIN138_RPC_URL}"; CHAIN_ID=138 ;;
cronos) RPC="${CRONOS_RPC_URL:-https://evm.cronos.org}"; CHAIN_ID=25 ;;
mainnet) RPC="${ETHEREUM_MAINNET_RPC}"; CHAIN_ID=1 ;;
*) echo "Unknown chain: $CHAIN"; exit 1 ;;
esac
echo "=== Parallel Deployment: $CHAIN (chain $CHAIN_ID) ==="
echo "RPC: $RPC"
echo ""
# Phase 1: Independent deployments (run in parallel)
echo "Phase 1: Core (parallel)..."
(
forge script script/DeployMulticall.s.sol:DeployMulticall --rpc-url "$RPC" --broadcast &
forge script script/DeployOracle.s.sol:DeployOracle --rpc-url "$RPC" --broadcast &
wait
) 2>&1 | tee /tmp/deploy-phase1.log || true
# Phase 2: Depends on Phase 1 (CREATE2 if needed for deterministic)
echo ""
echo "Phase 2: CREATE2Factory (if not exists)..."
if [ -z "${CREATE2_FACTORY:-}" ] || [ "$CREATE2_FACTORY" = "0x0000000000000000000000000000000000000000" ]; then
forge script script/Deploy.s.sol:Deploy --rpc-url "$RPC" --broadcast 2>&1 || true
fi
# Phase 3: Token/Reserve (require TOKEN_FACTORY etc.)
echo ""
echo "Phase 3: Token systems (require existing deps)..."
# DeployChain138, DeployISO4217WSystem, etc. — run if deps present
echo ""
echo "Deployment batch complete. Check logs for any failures."
echo "Note: Chain 138 may show 'Replacement transaction underpriced' if mempool has stuck tx."

View File

@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Run liquidity-gap tasks (G1G4) using .env. Phase and G4 amounts via tags (not .env).
#
# Usage:
# ./scripts/deployment/run-all-four-gaps.sh # run all phases (G4 interactive if no amounts)
# ./scripts/deployment/run-all-four-gaps.sh g1 g4 # run only G1 and G4
# ./scripts/deployment/run-all-four-gaps.sh g4 --eth 1 --weth 0.5 # G4 with amounts (no prompt)
# ./scripts/deployment/run-all-four-gaps.sh g4 # G4 with interactive prompt
#
# Phases: g1 (PMM on L2s), g2g3 (Trustless + Lockbox on L2s), g4 (fund mainnet LP).
# G4 amounts: use --eth, --weth, --eth-wei, --weth-wei (see fund-mainnet-lp.sh).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
load_deployment_env
DOTENV="${ENV_FILE:-$PROJECT_ROOT/.env}"
if [[ ! -f "$DOTENV" ]]; then
echo "No .env at $DOTENV. Create from .env.example and set PRIVATE_KEY, RPCs, token addresses. Or set ENV_FILE."
exit 1
fi
# Parse phase tags (g1, g2g3, g4); remaining args may include G2G3 tags (--lockbox, --chain) and G4 tags (--eth, --weth)
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
parse_phase_tags "$@"
REMAINING=("${PARSE_PHASE_TAGS_REMAINING[@]}")
parse_lockbox_tag "${REMAINING[@]}"
parse_chain_filter "${PARSE_LOCKBOX_REMAINING[@]}"
G4_ARGS=("${PARSE_CHAIN_FILTER_REMAINING[@]}")
G2G3_ARGS=()
[[ "${TRUSTLESS_DEPLOY_LOCKBOX:-1}" == "1" ]] && G2G3_ARGS+=(--lockbox) || G2G3_ARGS+=(--no-lockbox)
[[ ${#CHAIN_FILTER[@]} -gt 0 ]] && G2G3_ARGS+=(--chain "${CHAIN_FILTER[@]}")
echo "=============================================="
echo "Running liquidity gaps (secrets from .env)"
echo "=============================================="
if [[ "$RUN_G1" == "1" ]]; then
echo ""
echo "--- G1: Deploy PMM on L2s ---"
./scripts/deployment/deploy-pmm-all-l2s.sh || true
fi
if [[ "$RUN_G2G3" == "1" ]]; then
echo ""
echo "--- G2/G3: Deploy Trustless (+ Lockbox) on L2s ---"
./scripts/deployment/deploy-trustless-l2s.sh "${G2G3_ARGS[@]}" || true
fi
if [[ "$RUN_G4" == "1" ]]; then
echo ""
echo "--- G4: Fund mainnet LP ---"
./scripts/deployment/fund-mainnet-lp.sh "${G4_ARGS[@]}" || true
fi
echo ""
echo "Done. Update .env with any new contract addresses printed above."

View File

@@ -0,0 +1,114 @@
#!/usr/bin/env bash
# E2E live test: lock on 138 -> submit claim on mainnet -> (after 30 min) finalize -> release bond.
# Run from a host that can reach RPC_URL_138. Requires .env in smom-dbis-138 repo root.
# Best: cd /path/to/smom-dbis-138 then ./scripts/deployment/run-e2e-trustless-live-test.sh
#
# Usage:
# ./scripts/deployment/run-e2e-trustless-live-test.sh # run step 1 (lock), then print steps 23
# ./scripts/deployment/run-e2e-trustless-live-test.sh get-deposit-id <LOCK_TX_HASH> # print DEPOSIT_ID from lock tx
# DEPOSIT_ID=0x... AMOUNT_WEI=1000000000000000 ./scripts/deployment/run-e2e-trustless-live-test.sh claim # run step 2 only
# DEPOSIT_ID=0x... ./scripts/deployment/run-e2e-trustless-live-test.sh finalize # run step 3 only
set -euo pipefail
# Resolve repo root from script path so this works from any cwd (use full path to script when invoking)
SCRIPT_PATH="${BASH_SOURCE[0]}"
[[ -z "$SCRIPT_PATH" ]] && SCRIPT_PATH="$0"
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
if [[ ! -d "$REPO_ROOT" ]]; then
echo "Error: REPO_ROOT not found: $REPO_ROOT. Run from smom-dbis-138 repo, e.g. cd /path/to/smom-dbis-138 && ./scripts/deployment/run-e2e-trustless-live-test.sh"
exit 1
fi
cd "$REPO_ROOT" || { echo "Error: cannot cd to $REPO_ROOT"; exit 1; }
[[ -f .env ]] && set -a && source .env && set +a
# Use _MAINNET variants if unsuffixed not set (for .env that only has _MAINNET)
export BOND_MANAGER="${BOND_MANAGER:-${BOND_MANAGER_MAINNET:-}}"
export CHALLENGE_MANAGER="${CHALLENGE_MANAGER:-${CHALLENGE_MANAGER_MAINNET:-}}"
export INBOX_ETH="${INBOX_ETH:-${INBOX_ETH_MAINNET:-}}"
export LOCKBOX_138="${LOCKBOX_138:-}"
export RPC_URL_138="${RPC_URL_138:-${CHAIN_138_RPC_URL:-}}"
export ETHEREUM_MAINNET_RPC="${ETHEREUM_MAINNET_RPC:-}"
# Require key and RPCs so we fail with a clear message instead of "Invalid params"
[[ -n "${PRIVATE_KEY:-}" ]] || { echo "PRIVATE_KEY not set in .env"; exit 1; }
RECIPIENT=$(cast wallet address "$PRIVATE_KEY")
NONCE=$(cast keccak "e2e-$(date +%s)" | tr -d '\n\r')
# 0.001 ether in wei
AMOUNT_WEI="${AMOUNT_WEI:-1000000000000000}"
case "${1:-}" in
get-deposit-id)
[[ -n "${RPC_URL_138:-}" ]] || { echo "RPC_URL_138 not set"; exit 1; }
LOCK_TX="${2:-}"
[[ -n "$LOCK_TX" ]] || { echo "Usage: $0 get-deposit-id <LOCK_TX_HASH>"; exit 1; }
# Deposit event: first indexed param is depositId (topics[1])
DEPOSIT_ID_HEX=$(cast receipt "$LOCK_TX" --rpc-url "$RPC_URL_138" -j 2>/dev/null | jq -r '.logs[0].topics[1] // empty')
if [[ -z "$DEPOSIT_ID_HEX" ]]; then
echo "No Deposit log in tx or jq failed. Try: cast logs $LOCK_TX \"Deposit(uint256,address,uint256,address,bytes32,address,uint256)\" --rpc-url \$RPC_URL_138"
exit 1
fi
# cast expects uint256 as decimal or 0x; topics are 32-byte hex (0x + 64 chars)
echo "$DEPOSIT_ID_HEX"
exit 0
;;
claim)
[[ -n "${ETHEREUM_MAINNET_RPC:-}" ]] || { echo "ETHEREUM_MAINNET_RPC not set"; exit 1; }
[[ -n "${INBOX_ETH:-}" && -n "${BOND_MANAGER:-}" ]] || { echo "INBOX_ETH and BOND_MANAGER must be set for claim"; exit 1; }
if [[ -z "${DEPOSIT_ID:-}" ]]; then
echo "Set DEPOSIT_ID (from step 1 lock tx Deposit event). Example: DEPOSIT_ID=0x... $0 claim"
echo "To get DEPOSIT_ID from lock tx: cast logs <LOCK_TX_HASH> \"Deposit(uint256,address,uint256,address,bytes32,address,uint256)\" --rpc-url \$RPC_URL_138"
echo " Use the first decoded arg (depositId) as DEPOSIT_ID. Do NOT use AMOUNT_WEI as DEPOSIT_ID."
exit 1
fi
# Avoid common mistake: DEPOSIT_ID must be the event's depositId (large/hash), not the amount
if [[ "${DEPOSIT_ID:-}" == "1000000000000000" ]] || [[ "${DEPOSIT_ID:-}" == "$AMOUNT_WEI" ]]; then
echo "Error: DEPOSIT_ID looks like AMOUNT_WEI (0.001 ether). Set DEPOSIT_ID to the depositId from the Deposit event, not the amount."
exit 1
fi
BOND=$(cast call "$BOND_MANAGER" "getRequiredBond(uint256)(uint256)" "$AMOUNT_WEI" --rpc-url "$ETHEREUM_MAINNET_RPC")
# cast may append " [1e18]" etc.; use only the numeric part for --value
BOND="${BOND%% *}"
echo "BOND (required for claim): $BOND wei"
cast send "$INBOX_ETH" "submitClaim(uint256,address,uint256,address,bytes)" \
"$DEPOSIT_ID" 0x0000000000000000000000000000000000000000 "$AMOUNT_WEI" "$RECIPIENT" 0x \
--value "$BOND" --rpc-url "$ETHEREUM_MAINNET_RPC" --private-key "$PRIVATE_KEY"
echo "Claim submitted. Wait ~30 min then run: DEPOSIT_ID=$DEPOSIT_ID $0 finalize"
exit 0
;;
finalize)
[[ -n "${ETHEREUM_MAINNET_RPC:-}" ]] || { echo "ETHEREUM_MAINNET_RPC not set"; exit 1; }
[[ -n "${CHALLENGE_MANAGER:-}" && -n "${BOND_MANAGER:-}" ]] || { echo "CHALLENGE_MANAGER and BOND_MANAGER must be set for finalize"; exit 1; }
if [[ -z "${DEPOSIT_ID:-}" ]]; then
echo "Set DEPOSIT_ID. Example: DEPOSIT_ID=0x... $0 finalize"
exit 1
fi
cast send "$CHALLENGE_MANAGER" "finalizeClaim(uint256)" "$DEPOSIT_ID" \
--rpc-url "$ETHEREUM_MAINNET_RPC" --private-key "$PRIVATE_KEY"
cast send "$BOND_MANAGER" "releaseBond(uint256)" "$DEPOSIT_ID" \
--rpc-url "$ETHEREUM_MAINNET_RPC" --private-key "$PRIVATE_KEY"
echo "Finalized and bond released."
exit 0
;;
esac
# Step 1: Lock on 138
[[ -n "${RPC_URL_138:-}" ]] || { echo "RPC_URL_138 not set (required for lock on 138)"; exit 1; }
[[ -n "${LOCKBOX_138:-}" ]] || { echo "LOCKBOX_138 not set in .env"; exit 1; }
# Fail fast if RPC is not Chain 138 (avoids -32602 Invalid params from wrong chain)
CHAIN_ID=$(curl -s -m 5 -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' "$RPC_URL_138" 2>/dev/null | sed -n 's/.*"result":"\([^"]*\)".*/\1/p')
if [[ "$CHAIN_ID" != "0x8a" && "$CHAIN_ID" != "0x8A" ]]; then
echo "Error: RPC_URL_138 ($RPC_URL_138) returned chainId=$CHAIN_ID; expected 0x8a (138). Fix .env and retry."
exit 1
fi
echo "Step 1: Lock 0.001 ether on Chain 138 (LOCKBOX_138=$LOCKBOX_138)"
echo "RECIPIENT=$RECIPIENT NONCE=$NONCE"
# Use explicit --gas-limit to avoid eth_estimateGas -32602 Invalid params on some Chain 138 (Besu) nodes
cast send "$LOCKBOX_138" "depositNative(address,bytes32)" "$RECIPIENT" "$NONCE" \
--value 0.001ether --rpc-url "$RPC_URL_138" --private-key "$PRIVATE_KEY" \
--legacy --gas-price "${GAS_PRICE_138:-1000000000}" --gas-limit "${GAS_LIMIT_138:-200000}"
echo ""
echo "Get DEPOSIT_ID from the lock tx (run with the tx hash from above):"
echo " export DEPOSIT_ID=\$(./scripts/deployment/run-e2e-trustless-live-test.sh get-deposit-id <LOCK_TX_HASH>)"
echo " AMOUNT_WEI=$AMOUNT_WEI $0 claim"
echo "Or manually: cast logs <LOCK_TX_HASH> \"Deposit(uint256,address,uint256,address,bytes32,address,uint256)\" --rpc-url \$RPC_URL_138 (use first decoded arg)"
echo "Note: DEPOSIT_ID is the event's depositId, NOT the amount. Required bond for 0.001 ether is 1 ETH (min bond)."

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Run PMM phase (DeployDODOPMMIntegration) and optionally DeployPrivatePoolRegistryAndPools.
# Requires: .env with DODO_VENDING_MACHINE_ADDRESS, COMPLIANT_USDT_ADDRESS, COMPLIANT_USDC_ADDRESS,
# OFFICIAL_USDT_ADDRESS, OFFICIAL_USDC_ADDRESS (see docs/integration/DODO_PMM_INTEGRATION.md).
# For XAU pools: set DODOPMM_INTEGRATION_ADDRESS and XAU_ADDRESS_138 after the first run.
# Usage: ./scripts/deployment/run-pmm-and-pools.sh
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
load_deployment_env
# Reject unset, empty, or zero address (0x0 or 0x000...)
if [[ -z "${DODO_VENDING_MACHINE_ADDRESS:-}" ]]; then
echo "DODO_VENDING_MACHINE_ADDRESS not set. Set it to the DODO DVM factory on Chain 138 (see docs/deployment/ALL_MAINNETS_DEPLOYMENT_RUNBOOK.md)."
exit 1
fi
# Reject 0x0 or 0x000...000 (zero address)
if [[ "$(echo "${DODO_VENDING_MACHINE_ADDRESS}" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')" =~ ^0x0+$ ]]; then
echo "DODO_VENDING_MACHINE_ADDRESS is zero. Set it to the DVM factory on Chain 138."
exit 1
fi
echo "=== Deploy DODOPMMIntegration (Chain 138) ==="
bash "$SCRIPT_DIR/deploy-all-mainnets-with-mapper-oracle-pmm.sh" pmm
if [[ -n "${DODO_PMM_INTEGRATION:-}" || -n "${DODOPMM_INTEGRATION_ADDRESS:-}" ]]; then
addr="${DODO_PMM_INTEGRATION:-$DODOPMM_INTEGRATION_ADDRESS}"
echo ""
echo "DODOPMMIntegration at $addr. Create cUSDT/USDT and cUSDC/USDC pools via createCUSDTUSDTPool/createCUSDCUSDCPool (see docs/integration/DODO_PMM_INTEGRATION.md)."
if [[ -n "${XAU_ADDRESS_138:-}" ]]; then
echo "=== Deploy PrivatePoolRegistry and XAU-anchored pools ==="
forge script script/dex/DeployPrivatePoolRegistryAndPools.s.sol:DeployPrivatePoolRegistryAndPools \
--rpc-url "$RPC_URL_138" --broadcast --private-key "$PRIVATE_KEY" \
--with-gas-price "${GAS_PRICE_138:-1000000000}" --legacy -vvv || true
else
echo "Set XAU_ADDRESS_138 and DODOPMM_INTEGRATION_ADDRESS in .env to deploy XAU-anchored pools (DeployPrivatePoolRegistryAndPools)."
fi
else
echo "Set DODO_PMM_INTEGRATION or DODOPMM_INTEGRATION_ADDRESS in .env after deploy, then re-run for pool creation."
fi

View File

@@ -0,0 +1,143 @@
#!/usr/bin/env bash
# Run PMM full parity: Phase 1 (Chain 138) and Phase 2 (L2s) in full parallel where possible.
# Usage:
# ./scripts/deployment/run-pmm-full-parity-all-phases.sh # run all phases
# RUN_PHASE1=0 ./scripts/deployment/run-pmm-full-parity-all-phases.sh # skip Phase 1
# RUN_PHASE2=0 ./scripts/deployment/run-pmm-full-parity-all-phases.sh # skip Phase 2
# DRY_RUN=1 ./scripts/deployment/run-pmm-full-parity-all-phases.sh # print only
# ADD_LIQUIDITY_BASE_AMOUNT=1000000e6 ADD_LIQUIDITY_QUOTE_AMOUNT=1000000e6 ... # liquidity amounts (6 decimals)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
load_deployment_env
# Ensure .env is loaded (for PRIVATE_KEY, RPCs, etc.)
[[ -f ".env" ]] && set -a && source ".env" && set +a
RUN_PHASE1="${RUN_PHASE1:-1}"
RUN_PHASE2="${RUN_PHASE2:-1}"
DRY_RUN="${DRY_RUN:-}"
RPC_138="${RPC_URL_138:-${RPC_URL:-http://192.168.11.211:8545}}"
GAS_PRICE="${GAS_PRICE_138:-${GAS_PRICE:-1000000000}}"
INTEGRATION="${DODO_PMM_INTEGRATION_ADDRESS:-${DODO_PMM_INTEGRATION:-0x79cdbaFBaA0FdF9F55D26F360F54cddE5c743F7D}}"
POOL_CUSDTCUSDC="${POOL_CUSDTCUSDC:-0x9fcB06Aa1FD5215DC0E91Fd098aeff4B62fEa5C8}"
POOL_CUSDTUSDT="${POOL_CUSDTUSDT:-0xa3Ee6091696B28e5497b6F491fA1e99047250c59}"
POOL_CUSDCUSDC="${POOL_CUSDCUSDC:-0x90bd9Bf18Daa26Af3e814ea224032d015db58Ea5}"
export RPC_URL_138="$RPC_138"
export DODO_PMM_INTEGRATION_ADDRESS="$INTEGRATION"
export POOL_CUSDTCUSDC POOL_CUSDTUSDT POOL_CUSDCUSDC
log() { echo "[$(date +%H:%M:%S)] $*"; }
run_or_dry() {
if [[ -n "$DRY_RUN" ]]; then
log "[DRY RUN] $*"
return 0
fi
"$@"
}
# ---------- Phase 1: Chain 138 ----------
phase1() {
log "=== Phase 1: Chain 138 (verify pools, register, add liquidity) ==="
if [[ -z "${PRIVATE_KEY:-}" ]]; then
log "Skip Phase 1: PRIVATE_KEY not set"
return 0
fi
# 1a) Create all 3 pools in parallel (if not already created — scripts will fail if pool exists)
log "Creating PMM pools (parallel)..."
if [[ -z "$DRY_RUN" ]]; then
( forge script script/dex/CreateCUSDTCUSDCPool.s.sol:CreateCUSDTCUSDCPool \
--rpc-url "$RPC_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "$GAS_PRICE" -vv 2>&1 | tee /tmp/pmm-create-cusdt-cusdc.log ) &
PID1=$!
( forge script script/dex/CreateCUSDTUSDTPool.s.sol:CreateCUSDTUSDTPool \
--rpc-url "$RPC_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "$GAS_PRICE" -vv 2>&1 | tee /tmp/pmm-create-cusdt-usdt.log ) &
PID2=$!
( forge script script/dex/CreateCUSDCUSDCPool.s.sol:CreateCUSDCUSDCPool \
--rpc-url "$RPC_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "$GAS_PRICE" -vv 2>&1 | tee /tmp/pmm-create-cusdc-usdc.log ) &
PID3=$!
wait $PID1 2>/dev/null || true
wait $PID2 2>/dev/null || true
wait $PID3 2>/dev/null || true
else
log "[DRY RUN] forge script CreateCUSDTCUSDCPool ..."
log "[DRY RUN] forge script CreateCUSDTUSDTPool ..."
log "[DRY RUN] forge script CreateCUSDCUSDCPool ..."
fi
# 1b) Register pools with DODOPMMProvider (requires DODO_PMM_PROVIDER_ADDRESS)
if [[ -n "${DODO_PMM_PROVIDER_ADDRESS:-}" ]]; then
log "Registering pools with DODOPMMProvider..."
run_or_dry forge script script/liquidity/RegisterDODOPools.s.sol:RegisterDODOPools \
--rpc-url "$RPC_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "$GAS_PRICE" -vv
else
log "Skip register: DODO_PMM_PROVIDER_ADDRESS not set"
fi
# 1c) Add liquidity (optional: set ADD_LIQUIDITY_BASE_AMOUNT and ADD_LIQUIDITY_QUOTE_AMOUNT)
if [[ -n "${ADD_LIQUIDITY_BASE_AMOUNT:-}" && -n "${ADD_LIQUIDITY_QUOTE_AMOUNT:-}" ]]; then
log "Adding liquidity to PMM pools..."
run_or_dry forge script script/dex/AddLiquidityPMMPoolsChain138.s.sol:AddLiquidityPMMPoolsChain138 \
--rpc-url "$RPC_138" --broadcast --private-key "$PRIVATE_KEY" --with-gas-price "$GAS_PRICE" -vv
else
log "Skip add liquidity: set ADD_LIQUIDITY_BASE_AMOUNT and ADD_LIQUIDITY_QUOTE_AMOUNT (e.g. 1000000e6)"
fi
log "Phase 1 done."
}
# ---------- Phase 2: One chain (deploy cUSDT/cUSDC + DODOPMMIntegration) ----------
phase2_chain() {
local name="$1" chain_id="$2" rpc_var="$3"
local rpc="${!rpc_var:-}"
[[ -z "$rpc" ]] && return 0
log "[$name] Deploy cUSDT/cUSDC + DODOPMMIntegration (chain $chain_id)"
if [[ -n "$DRY_RUN" ]]; then
log "[DRY RUN] $name: deploy tokens + integration"
return 0
fi
local name_lower
name_lower=$(echo "$name" | tr '[:upper:]' '[:lower:]')
(
export DEPLOY_CUSDT_CUSDC_FILTER="$name"
export DEPLOY_PMM_L2S_FILTER="$name_lower"
cd "$REPO_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
load_deployment_env
./scripts/deployment/deploy-cusdt-cusdc-all-chains.sh 2>&1 | tee "/tmp/pmm-phase2-$name-tokens.log" || true
./scripts/deployment/deploy-pmm-all-l2s.sh --chain "$name_lower" 2>&1 | tee "/tmp/pmm-phase2-$name-pmm.log" || true
)
log "[$name] done."
}
# ---------- Phase 2: All L2s in parallel ----------
phase2() {
log "=== Phase 2: L2s (deploy cUSDT/cUSDC + DODOPMMIntegration per chain, parallel) ==="
CHAINS=(
"BSC:56:BSC_RPC_URL"
"POLYGON:137:POLYGON_MAINNET_RPC"
"BASE:8453:BASE_MAINNET_RPC"
"OPTIMISM:10:OPTIMISM_MAINNET_RPC"
"ARBITRUM:42161:ARBITRUM_MAINNET_RPC"
"AVALANCHE:43114:AVALANCHE_RPC_URL"
"CRONOS:25:CRONOS_RPC_URL"
"GNOSIS:100:GNOSIS_MAINNET_RPC"
)
PIDS=()
for entry in "${CHAINS[@]}"; do
IFS=: read -r name chain_id rpc_var <<< "$entry"
phase2_chain "$name" "$chain_id" "$rpc_var" &
PIDS+=($!)
done
for p in "${PIDS[@]}"; do wait "$p" 2>/dev/null || true; done
log "Phase 2 done."
}
# ---------- Main ----------
log "PMM full parity — Phase1=$RUN_PHASE1 Phase2=$RUN_PHASE2 DRY_RUN=$DRY_RUN"
[[ "$RUN_PHASE1" = "1" ]] && phase1
[[ "$RUN_PHASE2" = "1" ]] && phase2
log "All requested phases finished."

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env bash
# Run G2/G3 (Trustless + Lockbox) on the chains that previously failed: BSC, POLYGON, BASE, OPTIMISM, CRONOS.
# Fixes nonce for Cronos by clearing broadcast cache first; uses --slow and delay between chains to avoid 429/nonce issues.
# Tags: --delay <sec>, --lockbox / --no-lockbox.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$REPO_ROOT"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
parse_delay_tag "$@"
parse_lockbox_tag "${PARSE_DELAY_REMAINING[@]}"
TRUSTLESS_SCRIPT="script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge"
DELAY_BETWEEN_CHAINS="${DELAY_BETWEEN_CHAINS:-45}"
echo "=============================================="
echo "G2/G3 remaining: BSC, POLYGON, BASE, OPTIMISM, CRONOS (nonce fix for Cronos)"
echo "=============================================="
# Cronos: clear nonce cache then deploy
echo ""
echo "--- Fix nonce for Cronos (clear cache) ---"
./scripts/deployment/fix-nonce-and-retry.sh --chain cronos --script "$TRUSTLESS_SCRIPT" || true
echo ""
echo "--- Deploy Trustless + Lockbox on CRONOS (chain 25) ---"
rpc="${CRONOS_RPC_URL:-https://evm.cronos.org}"
weth="0x5C7F8A570d578ED84E63fdFA7b1eE72dEae1AE23"
TRUSTLESS_WETH_ADDRESS="$weth" TRUSTLESS_DEPLOY_LOCKBOX="${TRUSTLESS_DEPLOY_LOCKBOX:-1}" \
forge script script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge \
--rpc-url "$rpc" --chain-id 25 --broadcast --private-key "$PRIVATE_KEY" --slow -vvv || true
sleep "$DELAY_BETWEEN_CHAINS"
# BSC, Polygon, Base, Optimism with delay between each
for name in BSC POLYGON BASE OPTIMISM; do
echo ""
echo "--- Deploy Trustless + Lockbox on $name ---"
if [[ "${TRUSTLESS_DEPLOY_LOCKBOX:-1}" == "1" ]]; then
./scripts/deployment/deploy-trustless-l2s.sh --chain "$name" --lockbox || true
else
./scripts/deployment/deploy-trustless-l2s.sh --chain "$name" --no-lockbox || true
fi
sleep "$DELAY_BETWEEN_CHAINS"
done
echo ""
echo "Done. Update .env with BondManager, ChallengeManager, LiquidityPool, Inbox, Lockbox per chain."

View File

@@ -36,21 +36,23 @@ update_var() {
fi
}
# Update the provided variables
# Update the provided variables (use placeholders; set real values in .env and never commit).
if [ ! -z "$1" ] && [ "$1" == "update" ]; then
update_var "ETHEREUM_MAINNET_RPC" "https://mainnet.infura.io/v3/43b945b33d58463a9246cf5ca8aa6286"
update_var "RPC_URL_138" "http://192.168.11.250"
update_var "ETHERSCAN_API_KEY" "89HVZNN68DWKWVZHQRGQJ1B74FGKWBJV1W"
update_var "ETHEREUM_MAINNET_RPC" "https://mainnet.infura.io/v3/<INFURA_PROJECT_ID>"
update_var "RPC_URL_138" "http://192.168.11.211:8545"
update_var "ETHERSCAN_API_KEY" "<YOUR_ETHERSCAN_API_KEY>"
update_var "INFURA_PROJECT_ID" "<YOUR_INFURA_PROJECT_ID>"
update_var "INFURA_PROJECT_SECRET" "<YOUR_INFURA_PROJECT_SECRET>"
echo ""
echo "✓ Environment variables updated"
echo "✓ Environment variables updated with placeholders"
echo " Set real values in .env (INFURA_PROJECT_ID, INFURA_PROJECT_SECRET, ETHERSCAN_API_KEY); never commit secrets."
echo ""
echo "Run: ./scripts/deployment/check-env-requirements.sh to verify"
else
echo "Usage: $0 update"
echo ""
echo "This will update:"
echo " - ETHEREUM_MAINNET_RPC"
echo " - RPC_URL_138"
echo " - ETHERSCAN_API_KEY"
echo "This will set placeholders for:"
echo " - ETHEREUM_MAINNET_RPC (Infura), RPC_URL_138, ETHERSCAN_API_KEY"
echo " - INFURA_PROJECT_ID, INFURA_PROJECT_SECRET (for Infura RPC + Basic Auth)"
fi

View File

@@ -1,41 +1,48 @@
#!/bin/bash
# Verify All RPC Endpoints
# This script tests connectivity to all configured RPC endpoints
#!/usr/bin/env bash
# Verify All RPC Endpoints — tests connectivity to Mainnet, Chain 138, and all configured chain RPCs.
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
echo "=== RPC Endpoint Verification ==="
echo ""
# Load environment variables
if [ -f .env ]; then
export $(cat .env | grep -v '^#' | grep -v '^$' | xargs)
set -a
source .env
set +a
fi
# Use Infura with Basic Auth when INFURA_PROJECT_SECRET is set (fixes "error sending request" from Infura)
[ -f "${PROJECT_ROOT}/scripts/lib/infura.sh" ] && source "${PROJECT_ROOT}/scripts/lib/infura.sh"
if ! command -v cast &> /dev/null; then
echo "Error: cast command not found. Install foundry to verify RPC endpoints."
exit 1
fi
# Function to test RPC
# Function to test RPC (uses Infura Basic Auth URL when INFURA_PROJECT_SECRET is set)
test_rpc() {
local name=$1
local url=$2
[ -n "$url" ] && type ensure_infura_rpc_url &>/dev/null && url=$(ensure_infura_rpc_url "$url")
if [ -z "$url" ] || [ "$url" == "http://chain138.example.com:8545" ] || [[ "$url" == *"YOUR_PROJECT_ID"* ]]; then
if [ -z "$url" ] || [ "$url" == "http://chain138.example.com:8545" ] || [[ "$url" == *"YOUR_PROJECT_ID"* ]] || [[ "$url" == *"<"* ]]; then
echo "$name: Not configured"
return
fi
echo -n "Testing $name... "
BLOCK=$(cast block-number --rpc-url "$url" 2>&1)
if [ $? -eq 0 ] && [[ "$BLOCK" =~ ^[0-9]+$ ]]; then
BLOCK=$(cast block-number --rpc-url "$url" 2>&1) || true
if [[ "$BLOCK" =~ ^[0-9]+$ ]]; then
echo "✓ Connected (block: $BLOCK)"
else
echo "✗ Failed: $BLOCK"
echo "✗ Failed (${BLOCK:0:80})"
fi
return 0
}
echo "--- Required RPC Endpoints ---"
@@ -43,7 +50,7 @@ test_rpc "Ethereum Mainnet" "$ETHEREUM_MAINNET_RPC"
test_rpc "ChainID 138" "$RPC_URL_138"
echo ""
echo "--- Additional Network RPC Endpoints ---"
echo "--- Additional Network RPC Endpoints (Infura when set) ---"
test_rpc "Ethereum Sepolia" "$ETHEREUM_SEPOLIA_RPC"
test_rpc "Polygon Mainnet" "$POLYGON_MAINNET_RPC"
test_rpc "Polygon Amoy" "$POLYGON_AMOY_RPC"
@@ -51,6 +58,19 @@ test_rpc "Base Mainnet" "$BASE_MAINNET_RPC"
test_rpc "Base Sepolia" "$BASE_SEPOLIA_RPC"
test_rpc "Optimism Mainnet" "$OPTIMISM_MAINNET_RPC"
test_rpc "Optimism Sepolia" "$OPTIMISM_SEPOLIA_RPC"
test_rpc "Arbitrum Mainnet" "$ARBITRUM_MAINNET_RPC"
test_rpc "Arbitrum Sepolia" "$ARBITRUM_SEPOLIA_RPC"
test_rpc "Avalanche Mainnet" "$AVALANCHE_MAINNET_RPC"
test_rpc "Avalanche Fuji" "$AVALANCHE_FUJI_RPC"
test_rpc "BSC Mainnet" "$BSC_MAINNET_RPC"
test_rpc "Celo Mainnet" "$CELO_MAINNET_RPC"
test_rpc "Linea Mainnet" "$LINEA_MAINNET_RPC"
echo ""
echo "--- Other chain RPCs (aliases / public fallbacks) ---"
test_rpc "AVALANCHE_RPC_URL" "${AVALANCHE_RPC_URL:-}"
test_rpc "ARBITRUM_RPC" "${ARBITRUM_MAINNET_RPC:-$ARBITRUM_RPC}"
test_rpc "Cronos" "$CRONOS_RPC_URL"
echo ""
echo "=== Verification Complete ==="

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env bash
# Verify CCIPLogger on Etherscan-V2-supported chains (BSC, Polygon, Gnosis, Optimism, Base, Arbitrum, Avalanche).
# Prerequisite: Deploy CCIPLogger per chain (deploy-ccip-logger-all-chains.sh) and set in .env:
# CCIP_LOGGER_BSC, CCIP_BSC_ROUTER (and same for polygon, gnosis, optimism, base, arbitrum, avalanche).
# Mainnet: already verified (see COMPLETION_RUN_WITH_KEYS_20260223.md). Cronos: not Etherscan V2; use Cronoscan.
# Usage: cd smom-dbis-138 && ./scripts/deployment/verify-ccip-logger-other-chains.sh
# Requires: ETHERSCAN_API_KEY and PRIVATE_KEY in .env; npm/hardhat.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
if [[ -f .env ]]; then
set -a
source .env
set +a
fi
AUTH_SIGNER="${AUTHORIZED_SIGNER:-0x0000000000000000000000000000000000000000}"
SOURCE_CHAIN_SELECTOR="${CHAIN138_SELECTOR:-138}"
# Network -> env suffix (logger address, router). mainnet skipped (already verified); cronos skipped (no V2).
declare -A LOGGER_VAR=(
[bsc]=CCIP_LOGGER_BSC
[polygon]=CCIP_LOGGER_POLYGON
[gnosis]=CCIP_LOGGER_GNOSIS
[optimism]=CCIP_LOGGER_OPTIMISM
[base]=CCIP_LOGGER_BASE
[arbitrum]=CCIP_LOGGER_ARBITRUM
[avalanche]=CCIP_LOGGER_AVALANCHE
)
declare -A ROUTER_VAR=(
[bsc]=CCIP_BSC_ROUTER
[polygon]=CCIP_POLYGON_ROUTER
[gnosis]=CCIP_GNOSIS_ROUTER
[optimism]=CCIP_OPTIMISM_ROUTER
[base]=CCIP_BASE_ROUTER
[arbitrum]=CCIP_ARBITRUM_ROUTER
[avalanche]=CCIP_AVALANCHE_ROUTER
)
if [[ -z "${ETHERSCAN_API_KEY:-}" ]]; then
echo "ETHERSCAN_API_KEY not set. Add to .env and re-run." >&2
exit 1
fi
VERIFIED=0
SKIPPED=0
FAILED=0
for net in bsc polygon gnosis optimism base arbitrum avalanche; do
addr_var="${LOGGER_VAR[$net]}"
router_var="${ROUTER_VAR[$net]}"
addr="${!addr_var:-}"
router="${!router_var:-}"
if [[ -z "$addr" || "$addr" = "0x0000000000000000000000000000000000000000" ]]; then
echo "[$net] Skip (no $addr_var in .env)"
SKIPPED=$((SKIPPED + 1))
continue
fi
if [[ -z "$router" || "$router" = "0x0000000000000000000000000000000000000000" ]]; then
echo "[$net] Skip ($addr_var set but $router_var missing)"
SKIPPED=$((SKIPPED + 1))
continue
fi
echo "[$net] Verifying CCIPLogger $addr ..."
if npx hardhat verify --network "$net" "$addr" "$router" "$AUTH_SIGNER" "$SOURCE_CHAIN_SELECTOR" 2>&1; then
echo "[$net] Verified."
VERIFIED=$((VERIFIED + 1))
else
echo "[$net] Verify failed (may already be verified)."
FAILED=$((FAILED + 1))
fi
done
echo ""
echo "Summary: $VERIFIED verified, $SKIPPED skipped (no address/router), $FAILED failed."
echo "To deploy first: ./scripts/deployment/deploy-ccip-logger-all-chains.sh then set CCIP_LOGGER_* and CCIP_*_ROUTER in .env."

View File

@@ -3,9 +3,19 @@
set -e
cd "$(dirname "$0")/../.."
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR/../.."
[ -f "$SCRIPT_DIR/../lib/init.sh" ] && source "$SCRIPT_DIR/../lib/init.sh" 2>/dev/null || true
# Color codes
# Color codes (fallbacks if init.sh not loaded)
: "${GREEN:=\033[0;32m}"
: "${RED:=\033[0;31m}"
: "${YELLOW:=\033[1;33m}"
: "${NC:=\033[0m}"
log_info() { echo "$@"; }
log_success() { echo "$@"; }
log_warn() { echo "$@"; }
log_error() { echo "$@" >&2; }
echo "==================================================================="
echo " CHAIN-138 FULL DEPLOYMENT VERIFICATION"
@@ -13,9 +23,17 @@ echo "==================================================================="
# Load environment variables
if [ -f .env ]; then
set +u
source .env 2>/dev/null || true
set -u 2>/dev/null || true
fi
# Optional vars (allow unset for graceful checks)
CHAIN138_CCIP_REPORTER="${CHAIN138_CCIP_REPORTER:-}"
CCIP_CHAIN138_ROUTER="${CCIP_CHAIN138_ROUTER:-$CCIP_ROUTER}"
CHAIN138_CCIP_WETH9_BRIDGE="${CHAIN138_CCIP_WETH9_BRIDGE:-$CCIPWETH9_BRIDGE_CHAIN138}"
CHAIN138_CCIP_WETH10_BRIDGE="${CHAIN138_CCIP_WETH10_BRIDGE:-$CCIPWETH10_BRIDGE_CHAIN138}"
ERRORS=0
WARNINGS=0
SUCCESS=0
@@ -133,7 +151,7 @@ if [ -n "$CHAIN138_CCIP_REPORTER" ] && [ "$CHAIN138_CCIP_REPORTER" != "" ]; then
check_status "CCIPTxReporter" "warning" "$CHAIN138_CCIP_REPORTER (address in .env, cannot verify on-chain)"
fi
else
check_status "CCIPTxReporter" "error" "Not deployed (no address in .env)"
check_status "CCIPTxReporter" "warning" "Not deployed (optional; set CHAIN138_CCIP_REPORTER when deployed)"
fi
# CCIP Router on Chain-138
@@ -236,7 +254,7 @@ if [ -f "genesis.json" ]; then
check_status "WETH10 in Genesis" "warning" "Not found in genesis.json"
fi
else
check_status "Genesis File" "error" "genesis.json not found"
check_status "Genesis File" "warning" "genesis.json not found (optional for RPC-only Chain 138)"
fi
# Check .env configuration

View File

@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# Verify all four Cronos contracts via Etherscan-style API.
# Uses explorer-api.cronos.org (module/action, solidity-standard-json-input).
# Run from smom-dbis-138/
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source .env 2>/dev/null || true
if [ -z "${CRONOSCAN_API_KEY:-}" ]; then
echo "ERROR: CRONOSCAN_API_KEY not set. Set in .env (from explorer.cronos.org/register)."
exit 1
fi
export CRONOSCAN_API_KEY
echo "Cronos verification (Etherscan-style API)"
echo " API: https://explorer-api.cronos.org/mainnet/api"
echo " Chain: cronos (from foundry.toml)"
echo ""
verify() {
local addr="$1"
local contract="$2"
local extra_args="${3:-}"
echo "Verifying $contract at $addr..."
# shellcheck disable=SC2086
if forge verify-contract \
"$addr" "$contract" \
--chain cronos \
--etherscan-api-key "$CRONOSCAN_API_KEY" \
--skip-is-verified-check \
$extra_args \
--watch 2>&1; then
echo "$contract verified"
else
echo "$contract verification failed"
return 1
fi
}
FAIL=0
# WETH9 - no constructor args
verify "0x99B3511A2d315A497C8112C1fdd8D508d4B1E506" "contracts/tokens/WETH.sol:WETH" || FAIL=$((FAIL+1))
# WETH10 - no constructor args
verify "0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6" "contracts/tokens/WETH10.sol:WETH10" || FAIL=$((FAIL+1))
# CCIPWETH9Bridge - constructor(router, weth9, linkToken)
verify "0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e" "contracts/ccip/CCIPWETH9Bridge.sol:CCIPWETH9Bridge" \
"--constructor-args $(cast abi-encode 'constructor(address,address,address)' 0xE26B0A098D861d5C7d9434aD471c0572Ca6EAa67 0x99B3511A2d315A497C8112C1fdd8D508d4B1E506 0x8c80A01F461f297Df7F9DA3A4f740D7297C8Ac85)" || FAIL=$((FAIL+1))
# CCIPWETH10Bridge - constructor(router, weth10, linkToken)
verify "0x105F8A15b819948a89153505762444Ee9f324684" "contracts/ccip/CCIPWETH10Bridge.sol:CCIPWETH10Bridge" \
"--constructor-args $(cast abi-encode 'constructor(address,address,address)' 0xE26B0A098D861d5C7d9434aD471c0572Ca6EAa67 0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6 0x8c80A01F461f297Df7F9DA3A4f740D7297C8Ac85)" || FAIL=$((FAIL+1))
echo ""
if [ "$FAIL" -eq 0 ]; then
echo "All four Cronos contracts verified."
exit 0
else
echo "$FAIL contract(s) failed."
echo ""
echo "Manual verification (recommended):"
echo " 1. ./scripts/deployment/export-cronos-verification-sources.sh"
echo " 2. Open https://explorer.cronos.org/verifyContract"
echo " 3. Follow docs/deployment/CRONOS_VERIFICATION_RUNBOOK.md"
echo ""
exit 1
fi

View File

@@ -0,0 +1,72 @@
#!/usr/bin/env bash
# Verify deployed contracts on Avalanche, Arbitrum, Cronos.
# Requires ETHERSCAN_API_KEY (or SNOWTRACE_API_KEY, ARBISCAN_API_KEY, CRONOSCAN_API_KEY per chain).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
source .env 2>/dev/null || true
if [ -z "${ETHERSCAN_API_KEY:-}" ]; then
echo "ERROR: ETHERSCAN_API_KEY not set. Set in .env or export."
exit 1
fi
export SNOWTRACE_API_KEY="${SNOWTRACE_API_KEY:-$ETHERSCAN_API_KEY}"
export ARBISCAN_API_KEY="${ARBISCAN_API_KEY:-$ETHERSCAN_API_KEY}"
# Cronos not in Etherscan V2; needs separate CRONOSCAN_API_KEY from cronoscan.com (no fallback)
verify_one() {
local addr="$1"
local contract="$2"
local chain_arg="$3"
local chain_name="$4"
echo "Verifying $contract at $addr on $chain_name..."
# shellcheck disable=SC2086
forge verify-contract "$addr" "$contract" $chain_arg \
--etherscan-api-key "${ETHERSCAN_API_KEY}" \
--watch 2>/dev/null || echo " (may already be verified or need chain-specific API key)"
}
# Avalanche 43114
for addr in 0xa4B9DD039565AeD9641D45b57061f99d9cA6Df08 0x89dd12025bfCD38A168455A44B400e913ED33BE2 0xe0E93247376aa097dB308B92e6Ba36bA015535D0 0xAb57BF30F1354CA0590af22D8974c7f24DB2DbD7; do
case "$addr" in
0xa4B9DD039565AeD9641D45b57061f99d9cA6Df08) c="contracts/tokens/WETH.sol:WETH" ;;
0x89dd12025bfCD38A168455A44B400e913ED33BE2) c="contracts/tokens/WETH10.sol:WETH10" ;;
0xe0E93247376aa097dB308B92e6Ba36bA015535D0) c="contracts/ccip/CCIPWETH9Bridge.sol:CCIPWETH9Bridge" ;;
0xAb57BF30F1354CA0590af22D8974c7f24DB2DbD7) c="contracts/ccip/CCIPWETH10Bridge.sol:CCIPWETH10Bridge" ;;
esac
verify_one "$addr" "$c" "--chain avalanche" "Avalanche"
done
# Arbitrum 42161
for addr in 0x89dd12025bfCD38A168455A44B400e913ED33BE2 0xe0E93247376aa097dB308B92e6Ba36bA015535D0 0xAb57BF30F1354CA0590af22D8974c7f24DB2DbD7 0xa780ef19A041745d353c9432f2a7f5A241335ffE; do
case "$addr" in
0x89dd12025bfCD38A168455A44B400e913ED33BE2) c="contracts/tokens/WETH.sol:WETH" ;;
0xe0E93247376aa097dB308B92e6Ba36bA015535D0) c="contracts/tokens/WETH10.sol:WETH10" ;;
0xAb57BF30F1354CA0590af22D8974c7f24DB2DbD7) c="contracts/ccip/CCIPWETH9Bridge.sol:CCIPWETH9Bridge" ;;
0xa780ef19A041745d353c9432f2a7f5A241335ffE) c="contracts/ccip/CCIPWETH10Bridge.sol:CCIPWETH10Bridge" ;;
esac
verify_one "$addr" "$c" "--chain arbitrum" "Arbitrum"
done
# Cronos 25 — API: explorer-api.cronos.org/mainnet. Forge Blockscout verifier incompatible.
# Try: ./scripts/deployment/verify-cronos-contracts.sh (may fail; use manual fallback)
# See docs/04-configuration/CRONOS_EXPLORER_OPERATIONS.md
if [ -n "${CRONOSCAN_API_KEY:-}" ]; then
echo ""
echo "Cronos contracts: run ./scripts/deployment/verify-cronos-contracts.sh"
echo "If that fails, manual verification: export-cronos-verification-sources.sh then CRONOS_VERIFICATION_RUNBOOK.md"
echo " WETH9: 0x99B3511A2d315A497C8112C1fdd8D508d4B1E506"
echo " WETH10: 0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6"
echo " CCIPWETH9: 0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e"
echo " CCIPWETH10: 0x105F8A15b819948a89153505762444Ee9f324684"
echo ""
else
echo "Skipping Cronos: set CRONOSCAN_API_KEY (from explorer.cronos.org) for manual verification."
fi
echo "Verification complete."

View File

@@ -0,0 +1,121 @@
#!/usr/bin/env bash
# Verify deployed Trustless Bridge contracts (BondManager, LiquidityPool, Inbox, Lockbox) on each chain.
# Uses dotenv at smom-dbis-138/.env. Requires: cast (Foundry).
# Exit 0 if all checked addresses have code; non-zero if any missing.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
DOTENV="$REPO_ROOT/.env"
cd "$REPO_ROOT"
[[ -f "$DOTENV" ]] && set -a && source "$DOTENV" && set +a
PASS=0
FAIL=0
FAILED_CHAINS=""
check_addr() {
local label="$1"
local addr="$2"
local rpc="$3"
if [[ -z "$addr" || "$addr" == "0x"*"..." ]]; then return; fi
local code
code=$(cast code "$addr" --rpc-url "$rpc" 2>/dev/null || true)
if [[ -n "$code" && "${#code}" -gt 2 ]]; then
echo " OK $label $addr"
PASS=$((PASS+1))
return 0
else
echo " FAIL $label $addr (no code or RPC error)"
FAIL=$((FAIL+1))
return 1
fi
}
verify_chain() {
local name="$1"
local rpc="$2"
shift 2
if [[ -z "$rpc" ]]; then echo "Skip $name (no RPC)"; return; fi
echo "--- $name ---"
local any_fail=0
while [[ $# -ge 2 ]]; do
check_addr "$1" "$2" "$rpc" || any_fail=1
shift 2
done
if [[ $any_fail -ne 0 ]]; then FAILED_CHAINS="$FAILED_CHAINS $name"; fi
echo ""
}
# Mainnet (Ethereum)
verify_chain "Ethereum Mainnet" "${ETHEREUM_MAINNET_RPC:-}" \
"BOND_MANAGER" "${BOND_MANAGER_MAINNET:-}" \
"LIQUIDITY_POOL" "${LIQUIDITY_POOL_ETH_MAINNET:-}" \
"INBOX" "${INBOX_ETH_MAINNET:-}"
# Chain 138
verify_chain "Chain 138" "${RPC_URL_138:-${CHAIN_138_RPC_URL:-}}" \
"LOCKBOX_138" "${LOCKBOX_138:-}"
# BSC
verify_chain "BSC" "${BSC_RPC_URL:-}" \
"BOND_MANAGER" "${BSC_BOND_MANAGER:-}" \
"LIQUIDITY_POOL" "${BSC_LIQUIDITY_POOL_ETH:-}" \
"INBOX" "${BSC_INBOX_ETH:-}" \
"LOCKBOX" "${BSC_LOCKBOX:-}"
# Polygon
verify_chain "Polygon" "${POLYGON_MAINNET_RPC:-}" \
"BOND_MANAGER" "${POLYGON_BOND_MANAGER:-}" \
"LIQUIDITY_POOL" "${POLYGON_LIQUIDITY_POOL_ETH:-}" \
"INBOX" "${POLYGON_INBOX_ETH:-}" \
"LOCKBOX" "${POLYGON_LOCKBOX:-}"
# Base
verify_chain "Base" "${BASE_MAINNET_RPC:-}" \
"BOND_MANAGER" "${BASE_BOND_MANAGER:-}" \
"LIQUIDITY_POOL" "${BASE_LIQUIDITY_POOL_ETH:-}" \
"INBOX" "${BASE_INBOX_ETH:-}" \
"LOCKBOX" "${BASE_LOCKBOX:-}"
# Optimism
verify_chain "Optimism" "${OPTIMISM_MAINNET_RPC:-}" \
"BOND_MANAGER" "${OPTIMISM_BOND_MANAGER:-}" \
"LIQUIDITY_POOL" "${OPTIMISM_LIQUIDITY_POOL_ETH:-}" \
"INBOX" "${OPTIMISM_INBOX_ETH:-}" \
"LOCKBOX" "${OPTIMISM_LOCKBOX:-}"
# Cronos
verify_chain "Cronos" "${CRONOS_RPC_URL:-}" \
"BOND_MANAGER" "${CRONOS_BOND_MANAGER:-}" \
"LIQUIDITY_POOL" "${CRONOS_LIQUIDITY_POOL_ETH:-}" \
"INBOX" "${CRONOS_INBOX_ETH:-}" \
"LOCKBOX" "${CRONOS_LOCKBOX:-}"
# Arbitrum (addresses from deployment run; may not be in .env)
verify_chain "Arbitrum" "${ARBITRUM_MAINNET_RPC:-}" \
"BOND_MANAGER" "${ARBITRUM_BOND_MANAGER:-0x26Eb0AC01BAb5756c73945d48e2B8e28D6b32287}" \
"LIQUIDITY_POOL" "${ARBITRUM_LIQUIDITY_POOL_ETH:-0x866aCe8664FF40E0a8842705E0D140E614eCc67B}" \
"INBOX" "${ARBITRUM_INBOX_ETH:-0xb1061A71412E18F66FF8D043e3F0682532ECdaf7}" \
"LOCKBOX" "${ARBITRUM_LOCKBOX:-0x57f8b4DB2d92CAB6093405b53158ab3224D37D24}"
# Avalanche
verify_chain "Avalanche" "${AVALANCHE_RPC_URL:-${AVALANCHE_MAINNET_RPC:-}}" \
"BOND_MANAGER" "${AVALANCHE_BOND_MANAGER:-0xD1695ed8F7683EE5d1BF55ed34585B22F474a7ef}" \
"LIQUIDITY_POOL" "${AVALANCHE_LIQUIDITY_POOL_ETH:-0xb6D2f38b9015F32ccE8818509c712264E7fceeD3}" \
"INBOX" "${AVALANCHE_INBOX_ETH:-0x866aCe8664FF40E0a8842705E0D140E614eCc67B}" \
"LOCKBOX" "${AVALANCHE_LOCKBOX:-0x7e6fB8D80f81430e560F8232b2A4fd06249d74ce}"
# Gnosis
verify_chain "Gnosis" "${GNOSIS_MAINNET_RPC:-}" \
"BOND_MANAGER" "${GNOSIS_BOND_MANAGER:-0x73376eB92c16977B126dB9112936A20Fa0De3442}" \
"LIQUIDITY_POOL" "${GNOSIS_LIQUIDITY_POOL_ETH:-0xb689c1C69DAa08DEb5D8feA2aBF0F64bFD409727}" \
"INBOX" "${GNOSIS_INBOX_ETH:-0x4C38F9A5ed68A04cd28a72E8c68C459Ec34576f3}" \
"LOCKBOX" "${GNOSIS_LOCKBOX:-0x0CA60e6f8589c540200daC9D9Cb27BC2e48eE66A}"
echo "=============================================="
echo "Summary: $PASS passed, $FAIL failed"
if [[ -n "$FAILED_CHAINS" ]]; then
echo "Chains with failures:$FAILED_CHAINS"
exit 1
fi
exit 0

View File

@@ -13,9 +13,12 @@ load_env() {
local env_file="${1:-${PROJECT_ROOT}/.env}"
if [ -f "$env_file" ]; then
# Export variables, ignoring comments and empty lines
# Export variables, ignoring comments and empty lines.
# Disable set -e so a failing command in .env (e.g. command substitution) does not exit the shell.
set -a
source <(grep -v '^#' "$env_file" | grep -v '^$' | sed 's/^/export /')
set +e
source <(grep -v '^#' "$env_file" | grep -v '^$' | sed 's/^/export /') 2>/dev/null || true
set -e
set +a
fi
}

View File

@@ -0,0 +1,62 @@
# Deployment script library
Reusable helpers for deployment scripts: **tag-based CLI** (no .env placeholders for one-off values), **interactive prompts** when run without args, and **callable modular linking** so scripts can invoke each other with arguments.
## Conventions
- **Secrets and chain config** stay in `.env` (e.g. `PRIVATE_KEY`, RPC URLs, contract addresses).
- **One-off or per-run values** are passed via **script tags** (e.g. `--eth 1.5`, `--chain bsc polygon`, `--lockbox`), not .env.
- Scripts that accept amounts **prompt interactively** when run with no args and stdin is a TTY.
- Scripts are **callable** from other scripts by passing the same tags (e.g. `run-all-four-gaps.sh g4 --eth 1`).
## Modules
| File | Purpose |
|------|--------|
| `prompts.sh` | Tag parsers: `parse_fund_tags` (--eth, --weth, --dry-run), `prompt_fund_amounts`, `eth_to_wei`, `parse_phase_tags` (g1, g2g3, g4), `parse_chain_filter` (--chain bsc polygon ...), `parse_lockbox_tag` (--lockbox / --no-lockbox), `parse_link_tags` (--link, --dry-run), `parse_dry_run_tag`, `parse_deploy_tag` (--deploy), `parse_delay_tag` (--delay). `L2_CHAIN_NAMES`, `normalize_chain_name`. |
| `dotenv.sh` | `load_deployment_env`, `require_fund_lp_env`. |
| `costs.sh` | Gas and cost helpers (existing). |
## Validate syntax (one command)
- **From this repo** (`smom-dbis-138`):
`./scripts/deployment/check-syntax.sh`
- **From workspace root** (e.g. `proxmox`):
`./smom-dbis-138/scripts/deployment/check-syntax.sh`
Checks all tag-based deployment scripts and the lib with `bash -n`.
## Usage
```bash
# From any script in scripts/deployment:
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../lib/deployment/dotenv.sh"
source "$SCRIPT_DIR/../lib/deployment/prompts.sh"
load_deployment_env
# Parse G4 amounts from args, then prompt if still empty (TTY)
parse_fund_tags "$@"
prompt_fund_amounts
# Use FUND_ETH_AMOUNT_WEI, FUND_WETH_AMOUNT_WEI
```
## Example: G4 fund mainnet LP
- **Standalone:** `./scripts/deployment/fund-mainnet-lp.sh --eth 1.5 --weth 0.5`
- **Interactive:** `./scripts/deployment/fund-mainnet-lp.sh`
- **From run-all:** `./scripts/deployment/run-all-four-gaps.sh g4 --eth 1`
No `FUND_ETH_AMOUNT_WEI` / `FUND_WETH_AMOUNT_WEI` in .env.
## Other scripts (tags)
| Script | Tags |
|--------|------|
| deploy-pmm-all-l2s.sh | --chain bsc polygon ... (or DEPLOY_PMM_L2S_FILTER in .env) |
| live-test-trustless-bridge.sh | --check (optional: print LP stats and BondManager totalEthHeld); prints cast commands for lock → claim → finalize → release |
| deploy-trustless-l2s.sh | --chain, --lockbox / --no-lockbox |
| fund-ccip-bridges-with-link.sh | --link amount, --dry-run |
| fix-nonce-and-retry.sh | --chain, --script (positional still supported) |
| run-remaining-g2g3-with-nonce-fix.sh | --delay, --lockbox / --no-lockbox |
| check-balances-gas-and-deploy.sh | --deploy |

View File

@@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Load deployment .env and require common vars.
# Usage: source "$SCRIPT_DIR/lib/deployment/dotenv.sh"
# Optional: load_deployment_env [--repo-root <path>]
#
# Correct dotenv file (in order):
# 1. ENV_FILE if set and the file exists (e.g. export ENV_FILE=/path/to/.env)
# 2. PROJECT_ROOT/.env (repo root; PROJECT_ROOT = scripts/lib/deployment/../.. when unset)
# So: use repo-root .env by default; set ENV_FILE to use a different file.
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
[[ -z "${PROJECT_ROOT:-}" ]] && PROJECT_ROOT="$(cd "$_LIB_DIR/../.." && pwd)"
# Preferred .env: ENV_FILE if set and readable; else PROJECT_ROOT/.env (repo root).
load_deployment_env() {
local root="${PROJECT_ROOT}"
while [[ $# -gt 0 ]]; do
case "$1" in
--repo-root) root="$2"; shift 2 ;;
*) shift ;;
esac
done
export PROJECT_ROOT="$root"
local dotenv="${root}/.env"
[[ -n "${ENV_FILE:-}" && -f "${ENV_FILE}" ]] && dotenv="${ENV_FILE}"
if [[ -f "$dotenv" ]]; then
set -a
# shellcheck disable=SC1090
source "$dotenv"
set +a
fi
}
# Require vars for mainnet LP funding (G4). Fails with message if missing.
require_fund_lp_env() {
load_deployment_env
: "${LIQUIDITY_POOL_ETH_MAINNET:=${LIQUIDITY_POOL:-}}"
if [[ -z "${LIQUIDITY_POOL_ETH_MAINNET:-}" ]]; then
echo "Set LIQUIDITY_POOL_ETH_MAINNET (or LIQUIDITY_POOL) in .env" >&2
return 1
fi
if [[ -z "${ETHEREUM_MAINNET_RPC:-}" ]]; then
echo "Set ETHEREUM_MAINNET_RPC in .env" >&2
return 1
fi
if [[ -z "${PRIVATE_KEY:-}" ]]; then
echo "Set PRIVATE_KEY in .env" >&2
return 1
fi
return 0
}

View File

@@ -0,0 +1,247 @@
#!/usr/bin/env bash
# Deployment tag parsing and interactive prompts.
# Usage: source "$SCRIPT_DIR/lib/deployment/prompts.sh"
# Provides: parse_fund_tags, prompt_fund_amounts, eth_to_wei, parse_phase_tags
# Resolve lib and project paths when sourced
_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
[[ -z "${PROJECT_ROOT:-}" ]] && PROJECT_ROOT="$(cd "$_LIB_DIR/../.." && pwd)"
# Convert ETH string to wei (supports "1.5", "1.5eth", "1000000000000000000" or "1000000000000000000wei")
eth_to_wei() {
local val="${1:-0}"
if [[ -z "$val" || "$val" == "0" ]]; then
echo "0"
return 0
fi
if [[ "$val" == *wei ]]; then
echo "${val%wei}"
return 0
fi
if [[ "$val" == *eth ]]; then
val="${val%eth}"
fi
if command -v cast &>/dev/null; then
cast to-wei "$val" ether 2>/dev/null || echo "0"
else
# Fallback: 1 eth = 1e18 (bash can't do float well; use bc/python if available)
if command -v python3 &>/dev/null; then
python3 -c "import math; print(int(float('$val') * 10**18))" 2>/dev/null || echo "0"
else
echo "0"
fi
fi
}
# Parse --eth, --weth, --eth-wei, --weth-wei, --dry-run from "$@".
# Sets: FUND_ETH_AMOUNT_WEI, FUND_WETH_AMOUNT_WEI (exported), DRY_RUN=1 if --dry-run.
# Consumed args are removed from the array; use parse_fund_tags "${@}" before other parsers.
parse_fund_tags() {
export FUND_ETH_AMOUNT_WEI="${FUND_ETH_AMOUNT_WEI:-0}"
export FUND_WETH_AMOUNT_WEI="${FUND_WETH_AMOUNT_WEI:-0}"
export DRY_RUN="${DRY_RUN:-0}"
local args=()
while [[ $# -gt 0 ]]; do
case "$1" in
--eth)
FUND_ETH_AMOUNT_WEI="$(eth_to_wei "${2:-0}")"
shift 2
;;
--weth)
FUND_WETH_AMOUNT_WEI="$(eth_to_wei "${2:-0}")"
shift 2
;;
--eth-wei)
FUND_ETH_AMOUNT_WEI="${2:-0}"
shift 2
;;
--weth-wei)
FUND_WETH_AMOUNT_WEI="${2:-0}"
shift 2
;;
--dry-run)
DRY_RUN=1
shift
;;
*)
args+=("$1")
shift
;;
esac
done
# Return unconsumed args (caller can set PARSE_FUND_TAGS_REMAINING=( "${args[@]}" ) or use as needed)
PARSE_FUND_TAGS_REMAINING=("${args[@]}")
}
# Interactive prompt for ETH/WETH amounts (only if both are 0 and stdin is a TTY).
# Sets FUND_ETH_AMOUNT_WEI and FUND_WETH_AMOUNT_WEI (exported).
prompt_fund_amounts() {
local eth_wei="${FUND_ETH_AMOUNT_WEI:-0}"
local weth_wei="${FUND_WETH_AMOUNT_WEI:-0}"
if [[ -n "$eth_wei" && "$eth_wei" != "0" ]] || [[ -n "$weth_wei" && "$weth_wei" != "0" ]]; then
return 0
fi
if [[ ! -t 0 ]]; then
return 0
fi
echo "G4: Fund mainnet Liquidity Pool (ETH and/or WETH)."
read -r -p "ETH amount (e.g. 1.5 or 0 to skip): " eth_input
read -r -p "WETH amount (e.g. 0.5 or 0 to skip): " weth_input
export FUND_ETH_AMOUNT_WEI="$(eth_to_wei "${eth_input:-0}")"
export FUND_WETH_AMOUNT_WEI="$(eth_to_wei "${weth_input:-0}")"
}
# Parse phase tags: g1, g2, g3, g2g3, g4 from "$@".
# Sets: RUN_G1, RUN_G2G3, RUN_G4 (0 or 1). Unconsumed args left in PARSE_PHASE_TAGS_REMAINING.
parse_phase_tags() {
RUN_G1=0
RUN_G2G3=0
RUN_G4=0
local args=()
for arg in "$@"; do
case "${arg,,}" in
g1) RUN_G1=1 ;;
g2|g3|g2g3) RUN_G2G3=1 ;;
g4) RUN_G4=1 ;;
*) args+=("$arg") ;;
esac
done
# If no phase given, run all
if [[ "$RUN_G1" -eq 0 && "$RUN_G2G3" -eq 0 && "$RUN_G4" -eq 0 ]]; then
RUN_G1=1
RUN_G2G3=1
RUN_G4=1
fi
PARSE_PHASE_TAGS_REMAINING=("${args[@]}")
}
# Canonical L2 list for deploy-pmm, deploy-trustless, fund-ccip, etc.
L2_CHAIN_NAMES=( BSC POLYGON BASE OPTIMISM ARBITRUM AVALANCHE CRONOS GNOSIS )
# Parse --chain <name> [<name> ...] from "$@". Names case-insensitive (bsc, BSC, Polygon, etc.).
# Sets CHAIN_FILTER=() (empty = all) or CHAIN_FILTER=( BSC POLYGON ... ). Unconsumed in PARSE_CHAIN_FILTER_REMAINING.
normalize_chain_name() {
case "${1^^}" in
BSC) echo BSC ;;
POLYGON) echo POLYGON ;;
BASE) echo BASE ;;
OPTIMISM) echo OPTIMISM ;;
ARBITRUM) echo ARBITRUM ;;
AVALANCHE) echo AVALANCHE ;;
CRONOS) echo CRONOS ;;
GNOSIS) echo GNOSIS ;;
*) echo "" ;;
esac
}
parse_chain_filter() {
CHAIN_FILTER=()
local args=()
local collecting=0
for arg in "$@"; do
if [[ "$arg" == "--chain" ]]; then
collecting=1
elif [[ "$collecting" -eq 1 ]]; then
local n; n="$(normalize_chain_name "$arg")"
if [[ -n "$n" ]]; then
CHAIN_FILTER+=("$n")
else
args+=("$arg")
collecting=0
fi
else
args+=("$arg")
fi
done
PARSE_CHAIN_FILTER_REMAINING=("${args[@]}")
}
# Parse --lockbox / --no-lockbox. Sets TRUSTLESS_DEPLOY_LOCKBOX=1 or 0. Default from env or 0.
# Unconsumed in PARSE_LOCKBOX_REMAINING.
parse_lockbox_tag() {
TRUSTLESS_DEPLOY_LOCKBOX="${TRUSTLESS_DEPLOY_LOCKBOX:-0}"
local args=()
for arg in "$@"; do
case "$arg" in
--lockbox) TRUSTLESS_DEPLOY_LOCKBOX=1; ;;
--no-lockbox) TRUSTLESS_DEPLOY_LOCKBOX=0; ;;
*) args+=("$arg") ;;
esac
done
PARSE_LOCKBOX_REMAINING=("${args[@]}")
}
# Parse --link <amount> (ETH or wei if --link-wei), --dry-run. Sets LINK_AMOUNT_WEI, DRY_RUN.
# Default LINK_AMOUNT_WEI 10e18 (10 LINK) when unset. Unconsumed in PARSE_LINK_TAGS_REMAINING.
link_to_wei() {
local val="${1:-0}"
if [[ -z "$val" || "$val" == "0" ]]; then echo "0"; return; fi
if [[ "$val" == *wei ]]; then echo "${val%wei}"; return; fi
if command -v cast &>/dev/null; then
cast to-wei "$val" ether 2>/dev/null || echo "0"
elif command -v python3 &>/dev/null; then
python3 -c "import math; print(int(float('$val') * 10**18))" 2>/dev/null || echo "0"
else
echo "0"
fi
}
parse_link_tags() {
export LINK_AMOUNT_WEI="${LINK_AMOUNT_WEI:-10000000000000000000}"
export DRY_RUN="${DRY_RUN:-0}"
local args=()
local i=0
local argv=("$@")
while [[ $i -lt ${#argv[@]} ]]; do
local a="${argv[$i]}"
case "$a" in
--link)
[[ $((i+1)) -lt ${#argv[@]} ]] && LINK_AMOUNT_WEI="$(link_to_wei "${argv[$((i+1))]}")"
i=$((i+2)); ;;
--link-wei)
[[ $((i+1)) -lt ${#argv[@]} ]] && LINK_AMOUNT_WEI="${argv[$((i+1))]}"
i=$((i+2)); ;;
--dry-run) DRY_RUN=1; i=$((i+1)); ;;
*) args+=("$a"); i=$((i+1)); ;;
esac
done
PARSE_LINK_TAGS_REMAINING=("${args[@]}")
}
# Parse --dry-run only. Sets DRY_RUN=1. Unconsumed in PARSE_DRY_RUN_REMAINING.
parse_dry_run_tag() {
DRY_RUN="${DRY_RUN:-0}"
local args=()
for arg in "$@"; do
if [[ "$arg" == "--dry-run" ]]; then DRY_RUN=1; else args+=("$arg"); fi
done
PARSE_DRY_RUN_REMAINING=("${args[@]}")
}
# Parse --deploy. Sets DO_DEPLOY=1. Unconsumed in PARSE_DEPLOY_REMAINING.
parse_deploy_tag() {
DO_DEPLOY="${DO_DEPLOY:-0}"
local args=()
for arg in "$@"; do
if [[ "$arg" == "--deploy" ]]; then DO_DEPLOY=1; else args+=("$arg"); fi
done
PARSE_DEPLOY_REMAINING=("${args[@]}")
}
# Parse --delay <seconds>. Sets DELAY_BETWEEN_CHAINS. Unconsumed in PARSE_DELAY_REMAINING.
parse_delay_tag() {
DELAY_BETWEEN_CHAINS="${DELAY_BETWEEN_CHAINS:-45}"
local args=()
local i=0
local argv=("$@")
while [[ $i -lt ${#argv[@]} ]]; do
if [[ "${argv[$i]}" == "--delay" && $((i+1)) -lt ${#argv[@]} ]]; then
DELAY_BETWEEN_CHAINS="${argv[$((i+1))]}"
i=$((i+2))
else
args+=("${argv[$i]}")
i=$((i+1))
fi
done
PARSE_DELAY_REMAINING=("${args[@]}")
}

63
scripts/lib/infura.sh Normal file
View File

@@ -0,0 +1,63 @@
#!/usr/bin/env bash
# Infura RPC URL builder: uses INFURA_PROJECT_ID and optional INFURA_PROJECT_SECRET (Basic Auth).
# Usage: source "$SCRIPT_DIR/lib/infura.sh" # then call build_infura_rpc "avalanche-mainnet"
# When INFURA_PROJECT_SECRET is set, the URL uses Basic Auth (required for some operations e.g. eth_sendTransaction).
# Set INFURA_PROJECT_ID and optionally INFURA_PROJECT_SECRET in .env; never commit secrets.
build_infura_rpc() {
local host_path="${1:?Usage: build_infura_rpc <host-path> e.g. avalanche-mainnet}"
local id="${INFURA_PROJECT_ID:-}"
local secret="${INFURA_PROJECT_SECRET:-}"
if [[ -z "$id" ]]; then
return 1
fi
local auth=""
if [[ -n "$secret" && ! "$secret" =~ \$\{ ]]; then
local encoded
encoded=$(printf '%s' "$secret" | python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.stdin.read(), safe=''))" 2>/dev/null) || encoded="$secret"
auth="${id}:${encoded}@"
fi
echo "https://${auth}${host_path}.infura.io/v3/${id}"
}
# Given any RPC URL, if it is an Infura URL (https://HOST.infura.io/v3/PROJECT_ID) and
# INFURA_PROJECT_SECRET is set, return the same URL with Basic Auth so requests succeed.
# If the URL already contains @ (already has auth), or is not Infura, return as-is.
# Use this before passing .env RPC vars to cast/curl so Infura is accessed with the secret.
ensure_infura_rpc_url() {
local url="${1:-}"
[[ -z "$url" ]] && echo "" && return 0
[[ "$url" == *"@"* ]] && echo "$url" && return 0
if [[ "$url" =~ ^https://([a-zA-Z0-9.-]+)\.infura\.io/v3/([a-zA-Z0-9]+)$ ]]; then
local host="${BASH_REMATCH[1]}"
local id="${BASH_REMATCH[2]}"
local secret="${INFURA_PROJECT_SECRET:-}"
if [[ -n "$secret" && ! "$secret" =~ \$\{ ]]; then
local encoded
encoded=$(printf '%s' "$secret" | python3 -c "import sys, urllib.parse; print(urllib.parse.quote(sys.stdin.read(), safe=''))" 2>/dev/null) || encoded="$secret"
echo "https://${id}:${encoded}@${host}.infura.io/v3/${id}"
return 0
fi
fi
echo "$url"
}
# Build Infura Gas API URL for Ethereum mainnet (networks/1).
# INFURA_GAS_API can be set to full URL; otherwise uses INFURA_PROJECT_ID.
get_infura_gas_api_url() {
local url="${INFURA_GAS_API:-}"
if [[ -n "$url" ]]; then
if [[ "$url" == *"/v3/"* ]]; then
local key="${url#*v3/}"
key="${key%%/*}"
echo "https://gas.api.infura.io/v3/${key}/networks/1/suggestedGasFees"
return
fi
echo "$url"
return
fi
local id="${INFURA_PROJECT_ID:-}"
if [[ -n "$id" ]]; then
echo "https://gas.api.infura.io/v3/${id}/networks/1/suggestedGasFees"
fi
}

View File

@@ -33,5 +33,7 @@ source "${LIB_DIR}/config/regions.sh"
source "${LIB_DIR}/azure/cli.sh" 2>/dev/null || true
# Log that libraries are loaded (only in debug mode)
[ "${LOG_LEVEL:-1}" -le 0 ] && log_debug "Common libraries loaded from ${LIB_DIR}"
# Use default 1 if LOG_LEVEL is unset or not numeric (e.g. from .env)
_ll="${LOG_LEVEL:-1}"
[[ "$_ll" =~ ^[0-9]+$ ]] && [ "$_ll" -le 0 ] && log_debug "Common libraries loaded from ${LIB_DIR}" || true

20
scripts/load-env.sh Normal file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env bash
# Source the correct dotenv for smom-dbis-138 (single source for deploy, relay, token-aggregation).
# Uses repo-root .env unless ENV_FILE is already set. Export ENV_FILE so scripts using
# scripts/lib/deployment/dotenv.sh (load_deployment_env) use the same file.
# Usage: source scripts/load-env.sh (from smom-dbis-138)
# source smom-dbis-138/scripts/load-env.sh (from repo root)
# ENV_FILE=/path/to/.env source scripts/load-env.sh (override)
# Do not execute; source it so variables are in the current shell.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
[[ -z "${ENV_FILE:-}" ]] && ENV_FILE="${SCRIPT_DIR}/../.env"
export ENV_FILE
if [[ -f "$ENV_FILE" ]]; then
set -a
source "$ENV_FILE"
set +a
echo "Loaded: $ENV_FILE"
else
echo "WARN: $ENV_FILE not found" >&2
fi

138
scripts/mint-100-tokens.sh Executable file
View File

@@ -0,0 +1,138 @@
#!/bin/bash
# Mint 100 cUSDT and 100 cUSDC to a wallet address
# Usage: ./mint-100-tokens.sh
set -e
# Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Change to script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.." || exit 1
# Load .env
if [ -f .env ]; then
set -a
source .env
set +a
fi
# Try to use RPC_URL_138 first (if available), then RPC_URL, then fallback to public endpoint
if [ -n "$RPC_URL_138" ]; then
RPC_URL="$RPC_URL_138"
elif [ -n "$RPC_URL" ]; then
# Keep RPC_URL as is
:
else
RPC_URL="https://rpc-http-pub.d-bis.org"
fi
# Test RPC connectivity and fallback if needed
if ! curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
--max-time 3 "$RPC_URL" > /dev/null 2>&1; then
echo -e "${YELLOW}RPC endpoint not accessible, trying alternative...${NC}"
if [ "$RPC_URL" != "http://192.168.11.211:8545" ]; then
RPC_URL="http://192.168.11.211:8545"
else
RPC_URL="https://rpc-http-pub.d-bis.org"
fi
fi
# Token addresses (from .env or defaults)
COMPLIANT_USDT_ADDRESS=${COMPLIANT_USDT_ADDRESS:-"0x93E66202A11B1772E55407B32B44e5Cd8eda7f22"}
COMPLIANT_USDC_ADDRESS=${COMPLIANT_USDC_ADDRESS:-"0xf22258f57794CC8E06237084b353Ab30fFfa640b"}
# Recipient address
RECIPIENT="0xc2D6E6981D1A415967A683D615cf97bA9bC26F0f"
# Amount: 100 tokens with 6 decimals = 100000000
AMOUNT="100000000"
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Mint 100 cUSDT and 100 cUSDC ║${NC}"
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
if [ -z "$PRIVATE_KEY" ]; then
echo -e "${RED}Error: PRIVATE_KEY not set${NC}"
exit 1
fi
DEPLOYER=$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null)
echo -e "${BLUE}Deployer Address:${NC} $DEPLOYER"
echo -e "${BLUE}Recipient Address:${NC} $RECIPIENT"
echo -e "${BLUE}Amount:${NC} 100 tokens (each)"
echo ""
# Mint cUSDT directly to recipient
echo -e "${YELLOW}Minting 100 cUSDT to recipient...${NC}"
TX_OUTPUT=$(cast send "$COMPLIANT_USDT_ADDRESS" \
"mint(address,uint256)" \
"$RECIPIENT" \
"$AMOUNT" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
if echo "$TX_OUTPUT" | grep -qE "transactionHash"; then
TX_HASH=$(echo "$TX_OUTPUT" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}')
echo -e "${GREEN}✓ cUSDT mint successful${NC}"
echo " Transaction Hash: $TX_HASH"
else
echo -e "${RED}✗ cUSDT mint failed${NC}"
echo "$TX_OUTPUT"
exit 1
fi
echo ""
# Mint cUSDC directly to recipient
echo -e "${YELLOW}Minting 100 cUSDC to recipient...${NC}"
TX_OUTPUT=$(cast send "$COMPLIANT_USDC_ADDRESS" \
"mint(address,uint256)" \
"$RECIPIENT" \
"$AMOUNT" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
if echo "$TX_OUTPUT" | grep -qE "transactionHash"; then
TX_HASH=$(echo "$TX_OUTPUT" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}')
echo -e "${GREEN}✓ cUSDC mint successful${NC}"
echo " Transaction Hash: $TX_HASH"
else
echo -e "${RED}✗ cUSDC mint failed${NC}"
echo "$TX_OUTPUT"
exit 1
fi
echo ""
# Verify mints
echo -e "${YELLOW}Verifying mints...${NC}"
sleep 3
RECIPIENT_CUSDT=$(cast call "$COMPLIANT_USDT_ADDRESS" "balanceOf(address)" "$RECIPIENT" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
RECIPIENT_CUSDC=$(cast call "$COMPLIANT_USDC_ADDRESS" "balanceOf(address)" "$RECIPIENT" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
RECIPIENT_CUSDT_DISPLAY=$(echo "scale=2; $RECIPIENT_CUSDT / 1000000" | bc 2>/dev/null || echo "0")
RECIPIENT_CUSDC_DISPLAY=$(echo "scale=2; $RECIPIENT_CUSDC / 1000000" | bc 2>/dev/null || echo "0")
echo " Recipient cUSDT Balance: $RECIPIENT_CUSDT_DISPLAY tokens"
echo " Recipient cUSDC Balance: $RECIPIENT_CUSDC_DISPLAY tokens"
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Minting Complete! ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"

View File

@@ -0,0 +1,47 @@
#!/usr/bin/env node
/**
* Create node_modules/@emoney symlink so Hardhat can resolve @emoney/* imports
* (Foundry uses remappings in foundry.toml; Hardhat resolves from node_modules.)
* Run automatically via "pnpm install" / "prepare" script.
*/
const fs = require('fs');
const path = require('path');
const root = path.resolve(__dirname, '..');
const nodeModules = path.join(root, 'node_modules');
const emoneyDir = path.join(nodeModules, '@emoney');
const target = path.join(root, 'contracts', 'emoney');
if (!fs.existsSync(path.join(root, 'contracts', 'emoney'))) {
process.exit(0); // no contracts/emoney, skip
}
fs.mkdirSync(nodeModules, { recursive: true });
try {
const stat = fs.lstatSync(emoneyDir);
if (stat.isSymbolicLink()) {
const current = fs.readlinkSync(emoneyDir);
if (path.resolve(current) === path.resolve(target)) process.exit(0);
fs.unlinkSync(emoneyDir);
} else if (stat.isDirectory()) {
// leave existing real @emoney package alone
process.exit(0);
}
} catch (e) {
if (e.code !== 'ENOENT') throw e;
}
try {
fs.symlinkSync(target, emoneyDir, 'dir');
} catch (e) {
if (process.platform === 'win32') {
try {
fs.symlinkSync(target, emoneyDir, 'junction');
} catch (e2) {
console.warn('Could not create @emoney symlink:', e2.message);
}
} else {
console.warn('Could not create @emoney symlink:', e.message);
}
}

View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
# Run: lint, test, compile, then deploy (dry-run by default).
# Usage: ./scripts/run-lint-test-build-deploy.sh [--deploy-live]
set -e
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_ROOT"
export FOUNDRY_PROFILE=default
echo "=== 1. Compile ==="
forge build
echo "✅ Build OK"
echo ""
echo "=== 2. Lint ==="
forge lint 2>&1 | head -100 || true
echo "✅ Lint done"
echo ""
echo "=== 3. Test ==="
forge test 2>&1 | tail -50
echo "✅ Tests done"
echo ""
echo "=== 4. Deploy ==="
if [[ "${1:-}" == "--deploy-live" ]]; then
echo "Live deploy: run your preferred deploy script, e.g.:"
echo " bash scripts/deployment/deploy-tokens-and-weth-all-chains-skip-canonical.sh"
echo " or: forge script script/deploy/DeployCWTokens.s.sol:DeployCWTokens --rpc-url \$RPC_URL --chain-id 138 --broadcast --private-key \$PRIVATE_KEY --legacy"
exit 0
fi
echo "Dry-run: DeployCWTokens (simulation only)"
forge script script/deploy/DeployCWTokens.s.sol:DeployCWTokens --rpc-url "https://eth.llamarpc.com" --chain-id 1 2>&1 | tail -30
echo "✅ Deploy dry-run done (no broadcast)"

180
scripts/send-20m-tokens.sh Executable file
View File

@@ -0,0 +1,180 @@
#!/bin/bash
# Send 20M cUSDT and cUSDC to a wallet address
# Usage: ./send-20m-tokens.sh
set -e
# Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Change to script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.." || exit 1
# Load .env
if [ -f .env ]; then
set -a
source .env
set +a
fi
RPC_URL=${RPC_URL:-${RPC_URL_138:-"http://192.168.11.211:8545"}}
# Token addresses (from .env or defaults)
COMPLIANT_USDT_ADDRESS=${COMPLIANT_USDT_ADDRESS:-"0x93E66202A11B1772E55407B32B44e5Cd8eda7f22"}
COMPLIANT_USDC_ADDRESS=${COMPLIANT_USDC_ADDRESS:-"0xf22258f57794CC8E06237084b353Ab30fFfa640b"}
# Recipient address
RECIPIENT="0x4207aA9aC89B8bF4795dbAbBbE17fdd224E7947C"
# Amount: 20,000,000 tokens with 6 decimals = 20000000000000
AMOUNT="20000000000000"
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BLUE}║ Send 20M cUSDT and cUSDC ║${NC}"
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
if [ -z "$PRIVATE_KEY" ]; then
echo -e "${RED}Error: PRIVATE_KEY not set${NC}"
exit 1
fi
DEPLOYER=$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null)
echo -e "${BLUE}Deployer Address:${NC} $DEPLOYER"
echo -e "${BLUE}Recipient Address:${NC} $RECIPIENT"
echo -e "${BLUE}Amount:${NC} 20,000,000 tokens (each)"
echo ""
# Check balances before transfer
echo -e "${YELLOW}Checking balances...${NC}"
CUSDT_BALANCE=$(cast call "$COMPLIANT_USDT_ADDRESS" "balanceOf(address)" "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
CUSDC_BALANCE=$(cast call "$COMPLIANT_USDC_ADDRESS" "balanceOf(address)" "$DEPLOYER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
CUSDT_BALANCE_DISPLAY=$(echo "scale=2; $CUSDT_BALANCE / 1000000" | bc 2>/dev/null || echo "0")
CUSDC_BALANCE_DISPLAY=$(echo "scale=2; $CUSDC_BALANCE / 1000000" | bc 2>/dev/null || echo "0")
echo " Deployer cUSDT Balance: $CUSDT_BALANCE_DISPLAY tokens"
echo " Deployer cUSDC Balance: $CUSDC_BALANCE_DISPLAY tokens"
echo ""
# Check if we need to mint or transfer
USE_MINT=false
if [ "$(echo "$CUSDT_BALANCE < $AMOUNT" | bc 2>/dev/null || echo 1)" = "1" ]; then
echo -e "${YELLOW}Insufficient balance. Will mint tokens directly to recipient...${NC}"
USE_MINT=true
fi
if [ "$USE_MINT" = "true" ]; then
# Mint cUSDT directly to recipient
echo -e "${YELLOW}Minting 20M cUSDT to recipient...${NC}"
TX_OUTPUT=$(cast send "$COMPLIANT_USDT_ADDRESS" \
"mint(address,uint256)" \
"$RECIPIENT" \
"$AMOUNT" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
else
# Transfer cUSDT
echo -e "${YELLOW}Transferring 20M cUSDT...${NC}"
TX_OUTPUT=$(cast send "$COMPLIANT_USDT_ADDRESS" \
"transfer(address,uint256)" \
"$RECIPIENT" \
"$AMOUNT" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
fi
if echo "$TX_OUTPUT" | grep -qE "transactionHash"; then
TX_HASH=$(echo "$TX_OUTPUT" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}')
if [ "$USE_MINT" = "true" ]; then
echo -e "${GREEN}✓ cUSDT mint successful${NC}"
else
echo -e "${GREEN}✓ cUSDT transfer successful${NC}"
fi
echo " Transaction Hash: $TX_HASH"
else
echo -e "${RED}✗ cUSDT operation failed${NC}"
echo "$TX_OUTPUT"
exit 1
fi
echo ""
# Check if we need to mint cUSDC
USE_MINT_USDC=false
if [ "$(echo "$CUSDC_BALANCE < $AMOUNT" | bc 2>/dev/null || echo 1)" = "1" ]; then
USE_MINT_USDC=true
fi
if [ "$USE_MINT_USDC" = "true" ]; then
# Mint cUSDC directly to recipient
echo -e "${YELLOW}Minting 20M cUSDC to recipient...${NC}"
TX_OUTPUT=$(cast send "$COMPLIANT_USDC_ADDRESS" \
"mint(address,uint256)" \
"$RECIPIENT" \
"$AMOUNT" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
else
# Transfer cUSDC
echo -e "${YELLOW}Transferring 20M cUSDC...${NC}"
TX_OUTPUT=$(cast send "$COMPLIANT_USDC_ADDRESS" \
"transfer(address,uint256)" \
"$RECIPIENT" \
"$AMOUNT" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
fi
if echo "$TX_OUTPUT" | grep -qE "transactionHash"; then
TX_HASH=$(echo "$TX_OUTPUT" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}')
if [ "$USE_MINT_USDC" = "true" ]; then
echo -e "${GREEN}✓ cUSDC mint successful${NC}"
else
echo -e "${GREEN}✓ cUSDC transfer successful${NC}"
fi
echo " Transaction Hash: $TX_HASH"
else
echo -e "${RED}✗ cUSDC operation failed${NC}"
echo "$TX_OUTPUT"
exit 1
fi
echo ""
# Verify transfers
echo -e "${YELLOW}Verifying transfers...${NC}"
sleep 3
RECIPIENT_CUSDT=$(cast call "$COMPLIANT_USDT_ADDRESS" "balanceOf(address)" "$RECIPIENT" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
RECIPIENT_CUSDC=$(cast call "$COMPLIANT_USDC_ADDRESS" "balanceOf(address)" "$RECIPIENT" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
RECIPIENT_CUSDT_DISPLAY=$(echo "scale=2; $RECIPIENT_CUSDT / 1000000" | bc 2>/dev/null || echo "0")
RECIPIENT_CUSDC_DISPLAY=$(echo "scale=2; $RECIPIENT_CUSDC / 1000000" | bc 2>/dev/null || echo "0")
echo " Recipient cUSDT Balance: $RECIPIENT_CUSDT_DISPLAY tokens"
echo " Recipient cUSDC Balance: $RECIPIENT_CUSDC_DISPLAY tokens"
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Transfers Complete! ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"

View File

@@ -124,4 +124,8 @@ log_info "Next steps:"
log_info "1. Add liquidity to pools using addLiquidity()"
log_info "2. Monitor pool reserves and prices"
log_info "3. Enable trading and arbitrage"
log_info ""
log_info "For PMM coverage of all tokens (chain 138/651940), use:"
log_info " scripts/create-all-dodo-pools-from-token-api.sh"
log_info " (requires TOKEN_AGGREGATION_API_URL, CHAIN_ID, QUOTE_TOKEN_ADDRESS, DODO_PMM_INTEGRATION_ADDRESS, ENHANCED_SWAP_ROUTER_ADDRESS, UNIVERSAL_ASSET_REGISTRY_ADDRESS)"

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env node
/**
* Verify WETH9_138 fingerprint (symbol, name, decimals, optional bytecode hash).
* Bot/executor must run at startup and halt if fingerprint does not match expected.
* Usage: node verify-weth9-fingerprint.js [--no-exit]
* Exit 0 = match, 1 = mismatch or error.
*/
const WETH9_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const RPC_138 = process.env.RPC_URL_138 || 'https://rpc-http-pub.d-bis.org';
const RPC_MAINNET = process.env.ETHEREUM_MAINNET_RPC || 'https://eth.llamarpc.com';
const SELECTORS = { symbol: '0x95d89b41', name: '0x06fdde03', decimals: '0x313ce567' };
async function call(rpcUrl, to, data) {
const res = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_call', params: [{ to, data }, 'latest'], id: 1 }),
});
const d = await res.json();
if (d.error) throw new Error(d.error.message || JSON.stringify(d.error));
return d.result;
}
async function getCode(rpcUrl, address) {
const res = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_getCode', params: [address, 'latest'], id: 1 }),
});
const d = await res.json();
if (d.error) throw new Error(d.error.message || JSON.stringify(d.error));
return d.result;
}
function decodeString(hex) {
if (!hex || hex === '0x') return '';
try {
const ethers = require('ethers');
return ethers.AbiCoder.defaultAbiCoder().decode(['string'], hex)[0];
} catch (_) { return hex; }
}
function decodeUint8(hex) {
if (!hex || hex === '0x') return 0;
return parseInt(hex.slice(-2), 16);
}
async function getFingerprint(rpcUrl, address) {
const [symbolHex, nameHex, decimalsHex] = await Promise.all([
call(rpcUrl, address, SELECTORS.symbol),
call(rpcUrl, address, SELECTORS.name),
call(rpcUrl, address, SELECTORS.decimals),
]);
const ethers = require('ethers');
const code = await getCode(rpcUrl, address);
const codeHash = code && code !== '0x' ? ethers.keccak256(code) : null;
return {
symbol: decodeString(symbolHex),
name: decodeString(nameHex),
decimals: decodeUint8(decimalsHex),
codeHash,
};
}
async function main() {
const fp138 = await getFingerprint(RPC_138, WETH9_ADDRESS);
console.log('Chain 138 fingerprint:', JSON.stringify(fp138, null, 2));
const fpMain = await getFingerprint(RPC_MAINNET, WETH9_ADDRESS);
console.log('Ethereum mainnet fingerprint:', JSON.stringify(fpMain, null, 2));
const match = fp138.symbol === fpMain.symbol && fp138.name === fpMain.name
&& fp138.decimals === fpMain.decimals
&& (fp138.codeHash == null || fpMain.codeHash == null || fp138.codeHash === fpMain.codeHash);
if (match) {
console.log('Match: YES — WETH9_138 fingerprint matches expected.');
process.exit(0);
}
console.error('Halt: WETH9_138 fingerprint mismatch.');
process.exit(1);
}
main().catch((err) => { console.error(err); process.exit(1); });

279
scripts/update-oracle-price.sh Executable file
View File

@@ -0,0 +1,279 @@
#!/usr/bin/env bash
# Update Oracle Contract with Current ETH/USD Price
# This script fetches the current ETH price from CoinGecko and updates the oracle contract
# Usage: ./scripts/update-oracle-price.sh [rpc-url] [oracle-address] [private-key]
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Load .env if available
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR/.." || exit 1
if [ -f .env ]; then
set -a
source .env
set +a
fi
# RPC URL priority: command arg > RPC_URL_138 > RPC_URL > working defaults
DEFAULT_RPC="http://192.168.11.211:8545"
RPC_URL="${1:-${RPC_URL_138:-${RPC_URL:-$DEFAULT_RPC}}}"
ORACLE_ADDRESS="${2:-0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6}"
AGGREGATOR_ADDRESS="${AGGREGATOR_ADDRESS:-0x99b3511a2d315a497c8112c1fdd8d508d4b1e506}"
PRIVATE_KEY="${3:-${PRIVATE_KEY:-${DEPLOYER_PRIVATE_KEY:-}}}"
# Test RPC and fallback if needed
if ! curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
--max-time 3 "$RPC_URL" > /dev/null 2>&1; then
log_warn "Primary RPC not accessible, trying alternatives..."
# Try alternative RPCs
for ALT_RPC in "http://192.168.11.211:8545" "https://rpc-http-pub.d-bis.org"; do
if curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
--max-time 3 "$ALT_RPC" > /dev/null 2>&1; then
log_info "Using alternative RPC: $ALT_RPC"
RPC_URL="$ALT_RPC"
break
fi
done
fi
if [ -z "$PRIVATE_KEY" ]; then
log_error "Private key required"
log_info "Usage: $0 [rpc-url] [oracle-address] [private-key]"
log_info " OR: Set DEPLOYER_PRIVATE_KEY environment variable"
exit 1
fi
echo "========================================="
echo "Update Oracle Price Feed"
echo "========================================="
echo ""
log_info "RPC URL: $RPC_URL"
log_info "Oracle Address: $ORACLE_ADDRESS"
echo ""
# Check RPC connectivity
log_info "Checking RPC connectivity..."
if ! curl -s -X POST -H "Content-Type: application/json" \
--data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' \
"$RPC_URL" >/dev/null 2>&1; then
log_error "RPC is not accessible at $RPC_URL"
exit 1
fi
log_success "RPC is accessible"
# Fetch current ETH price from CoinGecko
log_info "Fetching ETH/USD price from CoinGecko..."
ETH_PRICE=$(curl -s 'https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd' | \
python3 -c "import sys, json; data = json.load(sys.stdin); print(data.get('ethereum', {}).get('usd', '0'))" 2>/dev/null || echo "0")
if [ "$ETH_PRICE" = "0" ] || [ -z "$ETH_PRICE" ]; then
log_error "Failed to fetch ETH price from CoinGecko"
log_info "Trying Binance API as fallback..."
ETH_PRICE=$(curl -s 'https://api.binance.com/api/v3/ticker/price?symbol=ETHUSDT' | \
python3 -c "import sys, json; data = json.load(sys.stdin); print(data.get('price', '0'))" 2>/dev/null || echo "0")
fi
if [ "$ETH_PRICE" = "0" ] || [ -z "$ETH_PRICE" ]; then
log_error "Failed to fetch ETH price from all sources"
exit 1
fi
log_success "ETH/USD Price: \$$ETH_PRICE"
# Convert to 8 decimals (oracle format)
PRICE_DECIMALS=$(python3 << PYEOF
price = float("$ETH_PRICE")
decimals = int(price * 100000000)
print(decimals)
PYEOF
)
log_info "Price in 8 decimals: $PRICE_DECIMALS"
echo ""
# Check current oracle price
log_info "Checking current oracle price..."
CURRENT_ORACLE_DATA=$(cast call "$ORACLE_ADDRESS" \
"latestRoundData()" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$CURRENT_ORACLE_DATA" ] && [ "$CURRENT_ORACLE_DATA" != "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ]; then
# Parse current price
CURRENT_ANSWER=$(echo "$CURRENT_ORACLE_DATA" | cut -c 131-194) # Extract answer field
CURRENT_PRICE=$(python3 << PYEOF
answer_hex = "$CURRENT_ANSWER"
answer_int = int(answer_hex, 16)
# Handle negative (if signed)
if answer_int > 2**255:
answer_int = answer_int - 2**256
price = answer_int / 100000000
print(price)
PYEOF
)
log_info "Current oracle price: \$$(printf '%.2f' $CURRENT_PRICE)"
# Check if update is needed (only update if difference > 1%)
PRICE_DIFF=$(python3 << PYEOF
current = float("$CURRENT_PRICE")
new = float("$ETH_PRICE")
diff = abs(new - current) / current * 100
print(diff)
PYEOF
)
if (( $(echo "$PRICE_DIFF < 1" | bc -l) )); then
log_warn "Price difference is less than 1% (${PRICE_DIFF}%)"
log_info "Skipping update to save gas"
exit 0
fi
fi
# Update oracle contract
log_info "Updating oracle contract..."
log_info "This will send a transaction to update the price feed..."
# Check if updateAnswer function exists, if not try transmit
if cast sig "updateAnswer(int256)" >/dev/null 2>&1; then
UPDATE_METHOD="updateAnswer"
elif cast sig "transmit(int256)" >/dev/null 2>&1; then
UPDATE_METHOD="transmit"
else
log_error "Could not determine oracle update method"
log_info "Please check the oracle contract ABI"
exit 1
fi
log_info "Using method: $UPDATE_METHOD"
# Check if account is authorized transmitter
if [ -n "$PRIVATE_KEY" ]; then
DEPLOYER_ADDR=$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null || echo "")
if [ -n "$DEPLOYER_ADDR" ]; then
log_info "Checking transmitter authorization..."
IS_TRANSMITTER=$(timeout 10 cast call "$AGGREGATOR_ADDRESS" "isTransmitter(address)(bool)" "$DEPLOYER_ADDR" --rpc-url "$RPC_URL" 2>/dev/null || echo "false")
if [ "$IS_TRANSMITTER" != "true" ]; then
log_warn "Account $DEPLOYER_ADDR is NOT an authorized transmitter"
log_info "Oracle requires transmitter role to update prices"
log_info "Options:"
log_info " 1. Use Oracle Publisher service (VMID 3500) - recommended"
log_info " 2. Use an authorized transmitter account private key"
log_info " 3. Add this account as transmitter (requires admin)"
log_info ""
log_info "Checking for transmitter addresses..."
TX_COUNT=0
for i in 0 1 2 3 4 5; do
TX_ADDR=$(timeout 10 cast call "$AGGREGATOR_ADDRESS" "transmitters(uint256)(address)" "$i" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$TX_ADDR" ] && [ "$TX_ADDR" != "0x0000000000000000000000000000000000000000" ]; then
log_info " Transmitter $TX_COUNT: $TX_ADDR"
TX_COUNT=$((TX_COUNT + 1))
fi
done
if [ $TX_COUNT -eq 0 ]; then
log_error "No transmitters found - oracle may not be configured"
fi
exit 1
else
log_success "Account is authorized transmitter"
fi
fi
fi
# Use aggregator address for updates (proxy is read-only)
UPDATE_CONTRACT="$AGGREGATOR_ADDRESS"
log_info "Updating aggregator contract: $UPDATE_CONTRACT"
# Send transaction (with timeout)
log_info "Sending transaction to aggregator (this may take 30-60 seconds)..."
TX_OUTPUT=$(timeout 90 cast send "$UPDATE_CONTRACT" \
"$UPDATE_METHOD(uint256)" \
"$PRICE_DECIMALS" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--legacy \
--gas-price 20000000000 \
2>&1)
# Check if transaction was sent
if [ $? -ne 0 ]; then
log_error "Transaction failed or timed out"
echo "$TX_OUTPUT"
exit 1
fi
# Extract transaction hash from output
TX_HASH=$(echo "$TX_OUTPUT" | grep -oE "transactionHash[[:space:]]+0x[0-9a-fA-F]{64}" | awk '{print $2}' || \
echo "$TX_OUTPUT" | grep -oE "0x[0-9a-fA-F]{64}" | head -1 || echo "")
# If still no hash, check for error messages
if [ -z "$TX_HASH" ]; then
if echo "$TX_OUTPUT" | grep -qi "error\|failed\|revert"; then
log_error "Transaction failed:"
echo "$TX_OUTPUT"
exit 1
elif echo "$TX_OUTPUT" | grep -qi "insufficient funds\|gas"; then
log_error "Transaction failed (gas/funds issue):"
echo "$TX_OUTPUT"
exit 1
else
log_warn "Could not extract transaction hash from output:"
echo "$TX_OUTPUT" | head -20
log_info "Transaction may have been sent - check explorer or try again"
exit 1
fi
fi
if [ -z "$TX_HASH" ]; then
log_error "Failed to send transaction"
exit 1
fi
log_success "Transaction sent: $TX_HASH"
# Wait for confirmation
log_info "Waiting for transaction confirmation..."
sleep 5
# Verify update
log_info "Verifying oracle update..."
NEW_ORACLE_DATA=$(cast call "$ORACLE_ADDRESS" \
"latestRoundData()" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$NEW_ORACLE_DATA" ]; then
NEW_ANSWER=$(echo "$NEW_ORACLE_DATA" | cut -c 131-194)
NEW_PRICE=$(python3 << PYEOF
answer_hex = "$NEW_ANSWER"
answer_int = int(answer_hex, 16)
if answer_int > 2**255:
answer_int = answer_int - 2**256
price = answer_int / 100000000
print(price)
PYEOF
)
log_success "Oracle updated successfully!"
log_info "New oracle price: \$$(printf '%.2f' $NEW_PRICE)"
else
log_warn "Could not verify oracle update (may need more time for confirmation)"
fi
echo ""
log_success "========================================="
log_success "Oracle Price Update Complete!"
log_success "========================================="
echo ""

View File

@@ -6,11 +6,18 @@
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../lib/init.sh"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
CONFIG_DIR="$PROJECT_ROOT/config"
GENESIS_FILE="$CONFIG_DIR/genesis.json"
# Minimal logging (used if init.sh is not sourced or fails)
log_success() { echo -e "\033[0;32m[✓]\033[0m $*"; }
log_error() { echo -e "\033[0;31m[✗]\033[0m $*" >&2; }
log_warn() { echo -e "\033[0;33m[⚠]\033[0m $*"; }
# Optional: load lib (may fail if .env or Azure deps are missing)
if [ -f "$SCRIPT_DIR/../lib/init.sh" ]; then
SCRIPT_DIR="$SCRIPT_DIR" source "$SCRIPT_DIR/../lib/init.sh" 2>/dev/null || true
fi
log_success "Validating Genesis File..."
@@ -60,29 +67,28 @@ else
exit 1
fi
# Check IBFT configuration
log_warn "Checking IBFT configuration..."
IBFT_CONFIG=$(jq -r '.config.ibft2' "$GENESIS_FILE")
# Check IBFT 2 / QBFT configuration
log_warn "Checking IBFT 2 / QBFT configuration..."
IBFT_CONFIG=$(jq -r '.config.ibft2 // .config.qbft // "null"' "$GENESIS_FILE")
if [ "$IBFT_CONFIG" != "null" ]; then
log_success "✓ IBFT 2.0 configuration exists"
# Check block period
BLOCK_PERIOD=$(jq -r '.config.ibft2.blockperiodseconds' "$GENESIS_FILE")
log_success "✓ IBFT 2.0 / QBFT configuration exists"
# Prefer qbft for Chain 138
BLOCK_KEY=".config.qbft.blockperiodseconds // .config.ibft2.blockperiodseconds"
EPOCH_KEY=".config.qbft.epochlength // .config.ibft2.epochlength"
BLOCK_PERIOD=$(jq -r "$BLOCK_KEY" "$GENESIS_FILE")
EPOCH_LENGTH=$(jq -r "$EPOCH_KEY" "$GENESIS_FILE")
if [ "$BLOCK_PERIOD" == "2" ]; then
log_success "✓ Block period is correct: $BLOCK_PERIOD seconds"
else
log_warn "⚠ Block period is $BLOCK_PERIOD (expected 2)"
fi
# Check epoch length
EPOCH_LENGTH=$(jq -r '.config.ibft2.epochlength' "$GENESIS_FILE")
if [ "$EPOCH_LENGTH" == "30000" ]; then
log_success "✓ Epoch length is correct: $EPOCH_LENGTH"
else
log_warn "⚠ Epoch length is $EPOCH_LENGTH (expected 30000)"
fi
else
log_error "✗ IBFT 2.0 configuration not found"
log_error "✗ IBFT 2.0 / QBFT configuration not found"
exit 1
fi

View File

@@ -0,0 +1,80 @@
#!/bin/bash
# Verify USDC contract deployment on ALL Mainnet (651940)
# This script helps check if USDC is deployed on ALL Mainnet
set -euo pipefail
CHAIN_ID=651940
RPC_URL="https://mainnet-rpc.alltra.global"
EXPLORER_URL="https://alltra.global"
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ ALL Mainnet (651940) USDC Verification Script ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
echo "Chain ID: $CHAIN_ID"
echo "RPC URL: $RPC_URL"
echo "Explorer: $EXPLORER_URL"
echo ""
# Check if cast (Foundry) is available
if ! command -v cast &> /dev/null; then
echo "⚠️ Warning: 'cast' command not found. Install Foundry to use RPC queries."
echo " Install: curl -L https://foundry.paradigm.xyz | bash && foundryup"
echo ""
echo "📋 Manual Verification Steps:"
echo " 1. Visit: $EXPLORER_URL"
echo " 2. Search for 'USDC' or 'USD Coin'"
echo " 3. Check token contract addresses"
echo " 4. Verify contract is verified and has standard USDC interface"
echo " 5. Record contract address and decimals (typically 6)"
echo ""
exit 0
fi
echo "🔍 Checking RPC connectivity..."
if ! cast block-number --rpc-url "$RPC_URL" > /dev/null 2>&1; then
echo "❌ Error: Cannot connect to RPC at $RPC_URL"
echo " Please check network connectivity or RPC endpoint"
exit 1
fi
BLOCK_NUM=$(cast block-number --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
ACTUAL_CHAIN_ID=$(cast chain-id --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
if [ "$ACTUAL_CHAIN_ID" != "$CHAIN_ID" ]; then
echo "⚠️ Warning: Chain ID mismatch (expected: $CHAIN_ID, got: $ACTUAL_CHAIN_ID)"
fi
echo "✅ RPC accessible (block: $BLOCK_NUM, chain: $ACTUAL_CHAIN_ID)"
echo ""
echo "📋 Common USDC Contract Addresses to Check:"
echo ""
echo "Standard USDC addresses (may differ on ALL Mainnet):"
echo " - Ethereum Mainnet: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
echo " - Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
echo " - Arbitrum: 0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
echo ""
echo "🔍 To verify USDC on ALL Mainnet:"
echo ""
echo "Method 1: Explorer Search"
echo " 1. Visit: $EXPLORER_URL"
echo " 2. Search for 'USDC' in token search"
echo " 3. Check contract verification status"
echo " 4. Verify token symbol, name, and decimals"
echo ""
echo "Method 2: RPC Query (if you have a suspected address)"
echo " cast call <ADDRESS> 'symbol()(string)' --rpc-url $RPC_URL"
echo " cast call <ADDRESS> 'name()(string)' --rpc-url $RPC_URL"
echo " cast call <ADDRESS> 'decimals()(uint8)' --rpc-url $RPC_URL"
echo ""
echo "Method 3: Check Token Lists"
echo " - Check if ALL Mainnet has a token list (similar to Uniswap token lists)"
echo " - Look for USDC in official token registries"
echo ""
echo "📝 After finding USDC address, update:"
echo " - alltra-lifi-settlement/src/config/chains.ts"
echo " Set: usdcAddress: '<FOUND_ADDRESS>'"
echo ""
echo "✅ Script complete. Manual verification required for USDC deployment."

View File

@@ -14,7 +14,7 @@ fi
RPC_URL="${RPC_URL:-${RPC_URL_138:-http://192.168.11.250:8545}}"
WETH9_ADDRESS="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
WETH9_BRIDGE="0x89dd12025bfCD38A168455A44B400e913ED33BE2"
WETH9_BRIDGE="0x971cD9D156f193df8051E48043C476e53ECd4693"
ETHEREUM_SELECTOR="5009297550715157269"
LINK_TOKEN="${LINK_TOKEN:-0x514910771AF9Ca656af840dff83E8264EcF986CA}"
AMOUNT_ETH="${1:-20000}"

View File

@@ -29,9 +29,9 @@ fi
# Configuration
RPC_URL="${RPC_URL:-${RPC_URL_138:-http://192.168.11.250:8545}}"
BRIDGE_ADDRESS="${CCIPWETH9_BRIDGE_CHAIN138:-0x89dd12025bfCD38A168455A44B400e913ED33BE2}"
LINK_TOKEN="${LINK_TOKEN:-0x514910771AF9Ca656af840dff83E8264EcF986CA}"
CCIP_ROUTER="${CCIP_ROUTER:-0x80226fc0Ee2b096224EeAc085Bb9a8cba1146f7D}"
BRIDGE_ADDRESS="${CCIPWETH9_BRIDGE_CHAIN138:-0x971cD9D156f193df8051E48043C476e53ECd4693}"
LINK_TOKEN="${LINK_TOKEN:-0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03}"
CCIP_ROUTER="${CCIP_ROUTER:-0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e}"
ETH_SELECTOR="5009297550715157269" # Ethereum Mainnet
echo "========================================="

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env node
// Verify CCIP/LiFi support for 138, 42793, 651940. Run: node scripts/verify-tezos-etherlink-support.js
const LIFI_URL = 'https://li.quest/v1/chains';
const CCIP_URL = 'https://docs.chain.link/ccip/supported-networks';
async function main() {
console.log('Tezos/Etherlink support check\n');
try {
const lifiRes = await fetch(LIFI_URL);
const lifi = await lifiRes.json();
const ids = (lifi.chains || []).map((c) => c.id || c.chainId).filter(Boolean);
console.log('LiFi chains include 138:', ids.includes(138));
console.log('LiFi chains include 42793:', ids.includes(42793));
console.log('LiFi chains include 651940:', ids.includes(651940));
} catch (e) {
console.log('LiFi error:', e.message);
}
try {
const ccipRes = await fetch(CCIP_URL);
const html = await ccipRes.text();
console.log('\nCCIP page mentions 42793:', html.includes('42793') || html.toLowerCase().includes('etherlink'));
console.log('CCIP page mentions 138:', html.includes('138'));
} catch (e) {
console.log('CCIP error:', e.message);
}
console.log('\nJumper: verify manually; see docs/07-ccip/TEZOS_JUMPER_SUPPORT_MATRIX.md');
}
main().catch((e) => { console.error(e); process.exit(1); });

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env node
/**
* Verify that WETH9 at 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 on Chain 138
* has the same bytecode as canonical WETH9 on Ethereum mainnet.
* Compares keccak256(code); if equal, the contract is canonical WETH9.
* Also outputs fingerprint (symbol, name, decimals) for bot/executor startup checks.
* See docs/treasury: do not assume canonical WETH9 until this (or verify-weth9-fingerprint.js) passes.
*/
const ethers = require('ethers');
const WETH9_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const RPC_138 = 'https://rpc-http-pub.d-bis.org';
const RPC_MAINNET = 'https://eth.llamarpc.com';
async function getCode(rpcUrl) {
const res = await fetch(rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_getCode',
params: [WETH9_ADDRESS, 'latest'],
id: 1,
}),
});
const data = await res.json();
if (data.error) throw new Error(data.error.message || JSON.stringify(data.error));
return data.result;
}
async function main() {
console.log('Fetching WETH9 bytecode from Chain 138 and Ethereum mainnet...');
const [code138, codeMainnet] = await Promise.all([
getCode(RPC_138),
getCode(RPC_MAINNET),
]);
const hash = (hex) => ethers.keccak256(hex);
const h138 = hash(code138);
const hMain = hash(codeMainnet);
console.log('Chain 138 bytecode length (bytes):', (code138.length - 2) / 2);
console.log('Ethereum main bytecode length (bytes):', (codeMainnet.length - 2) / 2);
console.log('Chain 138 keccak256(code):', h138);
console.log('Ethereum main keccak256(code):', hMain);
console.log('');
if (h138 === hMain) {
console.log('Match: YES — Chain 138 has canonical WETH9 bytecode at', WETH9_ADDRESS);
process.exit(0);
} else {
console.log('Match: NO — Chain 138 has WETH-like bytecode at that address, but not canonical WETH9.');
process.exit(1);
}
}
main().catch((err) => {
console.error(err);
process.exit(1);
});

View File

@@ -1,6 +1,8 @@
#!/usr/bin/env bash
# Wrap ETH to WETH9 and Bridge to Ethereum Mainnet
# Usage: ./wrap-and-bridge-weth9-to-mainnet.sh [amount_in_eth] [recipient_address] [private_key]
# Wrap ETH to WETH9 and Bridge to Ethereum Mainnet (Chain 138 → Ethereum Mainnet via CCIP)
# Usage: ./wrap-and-bridge-weth9-to-mainnet.sh <amount_in_eth> [recipient_address] [private_key]
# Env: PRIVATE_KEY (or 3rd arg), RPC_URL or RPC_URL_138, CCIPWETH9_BRIDGE_CHAIN138.
# Optional: WETH9_ADDRESS_CHAIN138 (if Chain 138 uses different WETH9), EXPLORER_URL_138.
set -euo pipefail
@@ -19,17 +21,20 @@ log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
log_error() { echo -e "${RED}[✗]${NC} $1"; }
# Load environment variables
if [ -f "$PROJECT_ROOT/.env" ]; then
source "$PROJECT_ROOT/.env"
# Load environment variables (try repo root = parent of scripts/, then workspace)
if [ -f "$SCRIPT_DIR/../.env" ]; then
set -a && source "$SCRIPT_DIR/../.env" && set +a
elif [ -f "$PROJECT_ROOT/.env" ]; then
set -a && source "$PROJECT_ROOT/.env" && set +a
elif [ -f "$PROJECT_ROOT/smom-dbis-138/.env" ]; then
source "$PROJECT_ROOT/smom-dbis-138/.env"
set -a && source "$PROJECT_ROOT/smom-dbis-138/.env" && set +a
fi
# Configuration
# Configuration (override WETH9_ADDRESS / WETH9_ADDRESS_CHAIN138 if Chain 138 uses a different WETH9)
RPC_URL="${RPC_URL:-${RPC_URL_138:-http://192.168.11.250:8545}}"
WETH9_ADDRESS="0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
WETH9_BRIDGE="0x89dd12025bfCD38A168455A44B400e913ED33BE2"
WETH9_ADDRESS="${WETH9_ADDRESS_CHAIN138:-${WETH9_ADDRESS:-0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2}}"
WETH9_BRIDGE="${CCIPWETH9_BRIDGE_CHAIN138:-0x971cD9D156f193df8051E48043C476e53ECd4693}"
EXPLORER_URL_138="${EXPLORER_URL_138:-https://explorer.d-bis.org}"
ETHEREUM_SELECTOR="5009297550715157269"
LINK_TOKEN="${LINK_TOKEN:-0x514910771AF9Ca656af840dff83E8264EcF986CA}"
@@ -108,22 +113,25 @@ if (( $(echo "$ETH_BALANCE < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); the
exit 1
fi
# Check WETH9 balance
# Check WETH9 balance (cast returns hex; parse to decimal for bc)
log_info "Checking WETH9 balance..."
WETH9_BALANCE=$(cast call "$WETH9_ADDRESS" "balanceOf(address)" "$SENDER" --rpc-url "$RPC_URL" 2>/dev/null | cast --to-dec 2>/dev/null || echo "0")
WETH9_BALANCE_RAW=$(cast call "$WETH9_ADDRESS" "balanceOf(address)(uint256)" "$SENDER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
WETH9_BALANCE=$(echo "$WETH9_BALANCE_RAW" | tr -d '\n\r' | sed 's/\[.*//' | grep -oE '^[0-9]+$' || echo "$WETH9_BALANCE_RAW" | cast --to-dec 2>/dev/null || echo "0")
[[ -z "$WETH9_BALANCE" ]] && WETH9_BALANCE=0
WETH9_BALANCE_ETH=$(echo "scale=6; $WETH9_BALANCE / 1000000000000000000" | bc 2>/dev/null || echo "0")
log_info "WETH9 Balance: $WETH9_BALANCE_ETH WETH9 ($WETH9_BALANCE wei)"
# Step 1: Wrap ETH to WETH9 (if needed)
NEED_TO_WRAP=false
if (( $(echo "$WETH9_BALANCE < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then
if (( $(echo "${WETH9_BALANCE:-0} < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then
NEED_TO_WRAP=true
WRAP_AMOUNT=$(echo "$AMOUNT_WEI - $WETH9_BALANCE" | bc 2>/dev/null || echo "$AMOUNT_WEI")
WRAP_AMOUNT=$(echo "$AMOUNT_WEI - ${WETH9_BALANCE:-0}" | bc 2>/dev/null || echo "$AMOUNT_WEI")
[[ -z "$WRAP_AMOUNT" ]] || [[ "$WRAP_AMOUNT" -lt "$AMOUNT_WEI" ]] 2>/dev/null && WRAP_AMOUNT="$AMOUNT_WEI"
WRAP_AMOUNT_ETH=$(echo "scale=6; $WRAP_AMOUNT / 1000000000000000000" | bc 2>/dev/null || echo "0")
log_info ""
log_info "Step 1: Wrapping ETH to WETH9..."
log_info " Amount to wrap: $WRAP_AMOUNT_ETH ETH"
log_info " Amount to wrap: $WRAP_AMOUNT_ETH ETH (wei: $WRAP_AMOUNT)"
# Check if we have enough ETH for wrapping
if (( $(echo "$ETH_BALANCE < $WRAP_AMOUNT" | bc -l 2>/dev/null || echo 1) )); then
@@ -131,13 +139,16 @@ if (( $(echo "$WETH9_BALANCE < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); t
exit 1
fi
log_info " Sending transaction..."
[[ -z "$WRAP_AMOUNT" ]] && WRAP_AMOUNT="$AMOUNT_WEI"
[[ "$WRAP_AMOUNT" = "0" ]] && WRAP_AMOUNT="$AMOUNT_WEI"
log_info " Sending transaction (value=$WRAP_AMOUNT wei)..."
WRAP_TX=$(cast send "$WETH9_ADDRESS" \
"deposit()" \
--value "$WRAP_AMOUNT" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--gas-price 20000000000 \
--gas-price "${GAS_PRICE_138:-1000000000}" \
--gas-limit "${GAS_LIMIT_138:-200000}" \
--legacy \
-vv 2>&1 || echo "")
@@ -147,10 +158,18 @@ if (( $(echo "$WETH9_BALANCE < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); t
log_info "Waiting for confirmation (15 seconds)..."
sleep 15
# Verify WETH9 balance
NEW_WETH9_BALANCE=$(cast call "$WETH9_ADDRESS" "balanceOf(address)" "$SENDER" --rpc-url "$RPC_URL" 2>/dev/null | cast --to-dec 2>/dev/null || echo "0")
# Verify WETH9 balance (same parsing as initial balance: balanceOf returns uint256)
NEW_WETH9_RAW=$(cast call "$WETH9_ADDRESS" "balanceOf(address)(uint256)" "$SENDER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
NEW_WETH9_BALANCE=$(echo "$NEW_WETH9_RAW" | tr -d '\n\r' | sed 's/\[.*//' | grep -oE '^[0-9]+$' || echo "$NEW_WETH9_RAW" | cast --to-dec 2>/dev/null || echo "0")
[[ -z "$NEW_WETH9_BALANCE" ]] && NEW_WETH9_BALANCE=0
NEW_WETH9_BALANCE_ETH=$(echo "scale=6; $NEW_WETH9_BALANCE / 1000000000000000000" | bc 2>/dev/null || echo "0")
log_success "✓ New WETH9 Balance: $NEW_WETH9_BALANCE_ETH WETH9"
if (( $(echo "${NEW_WETH9_BALANCE:-0} < $WRAP_AMOUNT" | bc -l 2>/dev/null || echo 1) )); then
log_error "WETH9 balance did not increase after wrap (got $NEW_WETH9_BALANCE_ETH WETH9). Wrap tx may have reverted."
log_info "Check wrap tx on explorer: $EXPLORER_URL_138/tx/$TX_HASH"
log_info "If the tx reverted, fix the cause (e.g. wrong WETH9 address on this chain) before re-running."
exit 1
fi
else
log_error "Failed to wrap ETH"
log_info "Output: $WRAP_TX"
@@ -163,7 +182,9 @@ fi
# Step 2: Approve bridge (if needed)
log_info ""
log_info "Step 2: Checking bridge approval..."
ALLOWANCE=$(cast call "$WETH9_ADDRESS" "allowance(address,address)" "$SENDER" "$WETH9_BRIDGE" --rpc-url "$RPC_URL" 2>/dev/null | cast --to-dec 2>/dev/null || echo "0")
ALLOWANCE_RAW=$(cast call "$WETH9_ADDRESS" "allowance(address,address)(uint256)" "$SENDER" "$WETH9_BRIDGE" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
ALLOWANCE=$(echo "$ALLOWANCE_RAW" | tr -d '\n\r' | grep -oE '^[0-9]+$' || echo "$ALLOWANCE_RAW" | cast --to-dec 2>/dev/null || echo "0")
[[ -z "$ALLOWANCE" ]] && ALLOWANCE=0
if (( $(echo "$ALLOWANCE < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then
log_info "Approving bridge to spend WETH9..."
@@ -175,7 +196,8 @@ if (( $(echo "$ALLOWANCE < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then
"$MAX_UINT256" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--gas-price 20000000000 \
--gas-price "${GAS_PRICE_138:-1000000000}" \
--gas-limit "${GAS_LIMIT_138:-200000}" \
--legacy \
-vv 2>&1 || echo "")
@@ -208,6 +230,27 @@ if (( $(echo "$LINK_BALANCE < 1000000000000000000" | bc -l 2>/dev/null || echo 0
log_warn "Recommended: At least 1-2 LINK for large transfers"
fi
# Chain 138 LINK - approve for CCIP fees (bridge or router pulls). Canonical on 138: 0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03 (see CHAIN138_TOKEN_ADDRESSES.md, LINK_TOKEN_STATUS_FINAL.md).
LINK_TOKEN_138="${LINK_TOKEN_CHAIN138:-${LINK_TOKEN:-0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03}}"
CCIP_ROUTER_138="${CCIP_ROUTER_ADDRESS:-0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e}"
MAX_UINT256="115792089237316195423570985008687907853269984665640564039457584007913129639935"
log_info "Approving LINK for CCIP fees (bridge + router)..."
cast send "$LINK_TOKEN_138" "approve(address,uint256)" "$WETH9_BRIDGE" "$MAX_UINT256" \
--rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --gas-price "${GAS_PRICE_138:-1000000000}" --gas-limit "${GAS_LIMIT_138:-200000}" --legacy -q 2>/dev/null || true
cast send "$LINK_TOKEN_138" "approve(address,uint256)" "$CCIP_ROUTER_138" "$MAX_UINT256" \
--rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --gas-price "${GAS_PRICE_138:-1000000000}" --gas-limit "${GAS_LIMIT_138:-200000}" --legacy -q 2>/dev/null || true
# Pre-bridge: confirm we have enough WETH9 (avoid bridging 0 or less)
FINAL_WETH9_RAW=$(cast call "$WETH9_ADDRESS" "balanceOf(address)(uint256)" "$SENDER" --rpc-url "$RPC_URL" 2>/dev/null || echo "0")
FINAL_WETH9=$(echo "$FINAL_WETH9_RAW" | tr -d '\n\r' | grep -oE '^[0-9]+$' || echo "$FINAL_WETH9_RAW" | cast --to-dec 2>/dev/null || echo "0")
[[ -z "$FINAL_WETH9" ]] && FINAL_WETH9=0
if (( $(echo "${FINAL_WETH9:-0} < $AMOUNT_WEI" | bc -l 2>/dev/null || echo 1) )); then
FINAL_ETH=$(echo "scale=6; $FINAL_WETH9 / 1000000000000000000" | bc 2>/dev/null || echo "0")
log_error "Insufficient WETH9 balance to bridge. Have $FINAL_ETH WETH9, need $AMOUNT_ETH WETH9."
log_info "Ensure wrap succeeded and balance is visible on-chain before re-running."
exit 1
fi
# Step 4: Bridge to Ethereum Mainnet
log_info ""
log_info "Step 4: Bridging WETH9 to Ethereum Mainnet..."
@@ -237,7 +280,8 @@ BRIDGE_TX=$(cast send "$WETH9_BRIDGE" \
"$AMOUNT_WEI" \
--rpc-url "$RPC_URL" \
--private-key "$PRIVATE_KEY" \
--gas-price 20000000000 \
--gas-price "${GAS_PRICE_138:-1000000000}" \
--gas-limit "${GAS_LIMIT_138:-300000}" \
--legacy \
-vv 2>&1 || echo "")
@@ -261,7 +305,7 @@ if echo "$BRIDGE_TX" | grep -qE "transactionHash"; then
log_success ""
log_info "Next Steps:"
log_info "1. Wait for CCIP confirmation (typically 1-5 minutes)"
log_info "2. Check transaction on Blockscout: https://explorer.d-bis.org/tx/$TX_HASH"
log_info "2. Check transaction on Blockscout: $EXPLORER_URL_138/tx/$TX_HASH"
log_info "3. Verify receipt on Ethereum Mainnet (Etherscan)"
log_info "4. Your WETH9 tokens will appear at $RECIPIENT on Ethereum Mainnet"
log_info ""