Add Oracle Aggregator and CCIP Integration

- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control.
- Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities.
- Created .gitmodules to include OpenZeppelin contracts as a submodule.
- Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment.
- Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks.
- Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring.
- Created scripts for resource import and usage validation across non-US regions.
- Added tests for CCIP error handling and integration to ensure robust functionality.
- Included various new files and directories for the orchestration portal and deployment scripts.
This commit is contained in:
defiQUG
2025-12-12 14:57:48 -08:00
parent a1466e4005
commit 1fb7266469
1720 changed files with 241279 additions and 16 deletions

View File

@@ -0,0 +1,162 @@
#!/usr/bin/env bash
# CCIP Configure Destination Script
# Configures a remote bridge address for a specific chain selector
#
# Usage:
# ./ccip-configure-destination.sh <chain-selector> <remote-bridge-address>
#
# Example (Chain 138 → Mainnet WETH9):
# export BRIDGE_ADDRESS=$CCIPWETH9_BRIDGE_CHAIN138
# ./ccip-configure-destination.sh 5009297550715157269 0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
# Load environment variables
ENV_FILE="${ENV_FILE:-$PROJECT_ROOT/.env}"
if [ -f "$ENV_FILE" ]; then
export $(grep -v '^#' "$ENV_FILE" | grep -E "^(RPC_URL|PRIVATE_KEY|CHAIN_ID|CCIP_ROUTER|LINK_TOKEN|WETH9_ADDRESS|WETH10_ADDRESS|CCIPWETH9_BRIDGE|CCIPWETH10_BRIDGE|ETHEREUM_MAINNET_SELECTOR|CHAIN138_SELECTOR)" | xargs)
fi
# Parse arguments
if [ $# -lt 2 ]; then
echo "Usage: $0 <chain-selector> <remote-bridge-address>"
echo ""
echo "Arguments:"
echo " chain-selector CCIP chain selector (e.g., 5009297550715157269 for Ethereum mainnet)"
echo " remote-bridge-address Address of the bridge contract on the destination chain"
echo ""
echo "Environment variables:"
echo " BRIDGE_ADDRESS Address of the bridge contract to configure (required)"
echo " RPC_URL RPC endpoint URL (required)"
echo " PRIVATE_KEY Private key for signing transactions (required)"
echo ""
echo "Examples:"
echo " # Configure Chain 138 WETH9 bridge → Mainnet"
echo " export BRIDGE_ADDRESS=\$CCIPWETH9_BRIDGE_CHAIN138"
echo " $0 5009297550715157269 0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6"
echo ""
echo " # Configure Mainnet WETH9 bridge → Chain 138"
echo " export BRIDGE_ADDRESS=\$CCIPWETH9_BRIDGE_MAINNET"
echo " $0 \$CHAIN138_SELECTOR 0x3304b747E565a97ec8AC220b0B6A1f6ffDB837e6"
exit 1
fi
CHAIN_SELECTOR="$1"
REMOTE_BRIDGE="$2"
# Validate required environment variables
if [ -z "${BRIDGE_ADDRESS:-}" ]; then
echo "Error: BRIDGE_ADDRESS not set"
echo "Set it to the bridge contract address you want to configure:"
echo " export BRIDGE_ADDRESS=\$CCIPWETH9_BRIDGE_CHAIN138"
echo " # or"
echo " export BRIDGE_ADDRESS=\$CCIPWETH10_BRIDGE_CHAIN138"
exit 1
fi
if [ -z "${RPC_URL:-}" ]; then
echo "Error: RPC_URL not set"
exit 1
fi
if [ -z "${PRIVATE_KEY:-}" ]; then
echo "Error: PRIVATE_KEY not set"
exit 1
fi
# Validate addresses
if ! cast --version &>/dev/null; then
echo "Error: cast (Foundry) not found. Please install Foundry:"
echo " curl -L https://foundry.paradigm.xyz | bash"
exit 1
fi
# Validate remote bridge address format
if ! cast --to-checksum-address "$REMOTE_BRIDGE" &>/dev/null; then
echo "Error: Invalid remote bridge address: $REMOTE_BRIDGE"
exit 1
fi
BRIDGE_ADDRESS=$(cast --to-checksum-address "$BRIDGE_ADDRESS")
echo "=========================================="
echo "CCIP Configure Destination"
echo "=========================================="
echo "Bridge Address: $BRIDGE_ADDRESS"
echo "Chain Selector: $CHAIN_SELECTOR"
echo "Remote Bridge: $REMOTE_BRIDGE"
echo "RPC URL: $RPC_URL"
echo ""
# Check if bridge contract exists
CODE=$(cast code "$BRIDGE_ADDRESS" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -z "$CODE" ] || [ "$CODE" = "0x" ]; then
echo "Error: No contract found at $BRIDGE_ADDRESS"
exit 1
fi
# Verify current configuration (if possible)
echo "Checking current remote bridge configuration..."
CURRENT_REMOTE=$(cast call "$BRIDGE_ADDRESS" \
"remoteBridges(uint64)(address)" \
"$CHAIN_SELECTOR" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "0x0000000000000000000000000000000000000000")
if [ "$CURRENT_REMOTE" != "0x0000000000000000000000000000000000000000" ]; then
echo "Current remote bridge: $CURRENT_REMOTE"
if [ "$CURRENT_REMOTE" = "$REMOTE_BRIDGE" ]; then
echo "✓ Remote bridge already configured correctly"
exit 0
else
echo "⚠ Warning: Remote bridge is already set to a different address"
read -p "Continue with update? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "Aborted"
exit 1
fi
fi
else
echo "No remote bridge configured for this chain selector"
fi
echo ""
echo "Configuring destination..."
echo ""
# Call configureDestination function
cast send "$BRIDGE_ADDRESS" \
"configureDestination(uint64,address)" \
"$CHAIN_SELECTOR" \
"$REMOTE_BRIDGE" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$RPC_URL" \
--gas-limit 200000
echo ""
echo "Waiting for transaction confirmation..."
sleep 5
# Verify configuration
VERIFIED_REMOTE=$(cast call "$BRIDGE_ADDRESS" \
"remoteBridges(uint64)(address)" \
"$CHAIN_SELECTOR" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "0x0000000000000000000000000000000000000000")
if [ "$VERIFIED_REMOTE" = "$REMOTE_BRIDGE" ]; then
echo "✓ Configuration successful!"
echo " Chain Selector $CHAIN_SELECTOR → Remote Bridge $REMOTE_BRIDGE"
else
echo "⚠ Warning: Configuration may not have been applied correctly"
echo " Expected: $REMOTE_BRIDGE"
echo " Got: $VERIFIED_REMOTE"
exit 1
fi
echo ""
echo "=========================================="
echo "Configuration Complete"
echo "=========================================="

View File

@@ -0,0 +1,131 @@
#!/usr/bin/env bash
# CCIP Estimate Fee Script
# Estimates the CCIP fee for bridging tokens to a destination chain
#
# Usage:
# ./ccip-estimate-fee.sh <chain-selector> <receiver-address> <amount-wei>
#
# Example:
# export BRIDGE_ADDRESS=$CCIPWETH9_BRIDGE_CHAIN138
# ./ccip-estimate-fee.sh 5009297550715157269 0xYourMainnetReceiverAddress 100000000000000000
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
# Load environment variables
ENV_FILE="${ENV_FILE:-$PROJECT_ROOT/.env}"
if [ -f "$ENV_FILE" ]; then
export $(grep -v '^#' "$ENV_FILE" | grep -E "^(RPC_URL|PRIVATE_KEY|CHAIN_ID|CCIP_ROUTER|LINK_TOKEN|WETH9_ADDRESS|WETH10_ADDRESS|FEE_TOKEN)" | xargs)
fi
# Parse arguments
if [ $# -lt 3 ]; then
echo "Usage: $0 <chain-selector> <receiver-address> <amount-wei>"
echo ""
echo "Arguments:"
echo " chain-selector CCIP chain selector (e.g., 5009297550715157269 for Ethereum mainnet)"
echo " receiver-address Address that will receive tokens on destination chain"
echo " amount-wei Amount to bridge in wei (e.g., 100000000000000000 for 0.1 tokens)"
echo ""
echo "Environment variables:"
echo " BRIDGE_ADDRESS Address of the bridge contract (required)"
echo " RPC_URL RPC endpoint URL (required)"
echo " FEE_TOKEN Fee token address (0x0 for native, or LINK token address)"
echo ""
echo "Examples:"
echo " # Estimate fee for 0.1 WETH9 from Chain 138 to Mainnet"
echo " export BRIDGE_ADDRESS=\$CCIPWETH9_BRIDGE_CHAIN138"
echo " $0 5009297550715157269 0xYourMainnetAddress 100000000000000000"
exit 1
fi
CHAIN_SELECTOR="$1"
RECEIVER="$2"
AMOUNT="$3"
# Validate required environment variables
if [ -z "${BRIDGE_ADDRESS:-}" ]; then
echo "Error: BRIDGE_ADDRESS not set"
echo "Set it to the bridge contract address:"
echo " export BRIDGE_ADDRESS=\$CCIPWETH9_BRIDGE_CHAIN138"
echo " # or"
echo " export BRIDGE_ADDRESS=\$CCIPWETH10_BRIDGE_CHAIN138"
exit 1
fi
if [ -z "${RPC_URL:-}" ]; then
echo "Error: RPC_URL not set"
exit 1
fi
# Default to LINK token if FEE_TOKEN not set
FEE_TOKEN="${FEE_TOKEN:-${LINK_TOKEN:-0x0000000000000000000000000000000000000000}}"
# Validate addresses
if ! cast --version &>/dev/null; then
echo "Error: cast (Foundry) not found. Please install Foundry:"
echo " curl -L https://foundry.paradigm.xyz | bash"
exit 1
fi
BRIDGE_ADDRESS=$(cast --to-checksum-address "$BRIDGE_ADDRESS")
RECEIVER=$(cast --to-checksum-address "$RECEIVER")
echo "=========================================="
echo "CCIP Estimate Fee"
echo "=========================================="
echo "Bridge Address: $BRIDGE_ADDRESS"
echo "Chain Selector: $CHAIN_SELECTOR"
echo "Receiver: $RECEIVER"
echo "Amount: $AMOUNT wei"
echo "Fee Token: $FEE_TOKEN"
echo ""
# Check if bridge has estimateCcipFee function
# If not, we'll need to call router.getFee directly
HAS_ESTIMATE_FUNCTION=$(cast sig "estimateCcipFee(uint64,address,uint256)(uint256)" 2>/dev/null || echo "")
if [ -n "$HAS_ESTIMATE_FUNCTION" ]; then
echo "Using bridge's estimateCcipFee function..."
FEE=$(cast call "$BRIDGE_ADDRESS" \
"estimateCcipFee(uint64,address,uint256)(uint256)" \
"$CHAIN_SELECTOR" \
"$RECEIVER" \
"$AMOUNT" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "0")
else
echo "Bridge doesn't have estimateCcipFee, calling router directly..."
echo "⚠ Note: This requires constructing the full message, which may not be possible without bridge contract details"
echo "Please implement estimateCcipFee in your bridge contract"
exit 1
fi
if [ "$FEE" = "0" ] || [ -z "$FEE" ]; then
echo "Error: Failed to estimate fee"
exit 1
fi
# Convert to human-readable format
FEE_DECIMAL=$(cast --to-dec "$FEE" 2>/dev/null || echo "$FEE")
echo ""
echo "=========================================="
echo "Fee Estimate"
echo "=========================================="
echo "Fee (wei): $FEE"
echo "Fee (decimal): $FEE_DECIMAL"
# If using LINK token, show in LINK units (18 decimals)
if [ "$FEE_TOKEN" != "0x0000000000000000000000000000000000000000" ]; then
FEE_LINK=$(echo "scale=8; $FEE_DECIMAL / 1000000000000000000" | bc 2>/dev/null || echo "N/A")
echo "Fee (LINK): $FEE_LINK LINK"
else
FEE_ETH=$(echo "scale=8; $FEE_DECIMAL / 1000000000000000000" | bc 2>/dev/null || echo "N/A")
echo "Fee (ETH): $FEE_ETH ETH"
fi
echo ""
echo "=========================================="

View File

@@ -0,0 +1,272 @@
#!/usr/bin/env bash
# CCIP Send Script
# Sends tokens via CCIP bridge to a destination chain
#
# Usage:
# ./ccip-send.sh --selector <chain-selector> --receiver <address> --amount <wei> [--dry-run]
#
# Example:
# export BRIDGE_ADDRESS=$CCIPWETH9_BRIDGE_CHAIN138
# ./ccip-send.sh --selector 5009297550715157269 --receiver 0xYourMainnetAddress --amount 100000000000000000
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
# Load environment variables
ENV_FILE="${ENV_FILE:-$PROJECT_ROOT/.env}"
if [ -f "$ENV_FILE" ]; then
export $(grep -v '^#' "$ENV_FILE" | grep -E "^(RPC_URL|PRIVATE_KEY|CHAIN_ID|CCIP_ROUTER|LINK_TOKEN|WETH9_ADDRESS|WETH10_ADDRESS|FEE_TOKEN)" | xargs)
fi
# Default values
DRY_RUN=false
SELECTOR=""
RECEIVER=""
AMOUNT=""
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--selector)
SELECTOR="$2"
shift 2
;;
--receiver)
RECEIVER="$2"
shift 2
;;
--amount)
AMOUNT="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
*)
echo "Unknown argument: $1"
echo ""
echo "Usage: $0 --selector <chain-selector> --receiver <address> --amount <wei> [--dry-run]"
echo ""
echo "Arguments:"
echo " --selector <chain-selector> CCIP chain selector (required)"
echo " --receiver <address> Receiver address on destination chain (required)"
echo " --amount <wei> Amount to bridge in wei (required)"
echo " --dry-run Simulate transaction without sending (optional)"
echo ""
echo "Environment variables:"
echo " BRIDGE_ADDRESS Bridge contract address (required)"
echo " RPC_URL RPC endpoint URL (required)"
echo " PRIVATE_KEY Private key for signing (required)"
echo " FEE_TOKEN Fee token address (0x0 for native, or LINK)"
echo ""
echo "Examples:"
echo " # Dry run: estimate without sending"
echo " export BRIDGE_ADDRESS=\$CCIPWETH9_BRIDGE_CHAIN138"
echo " $0 --selector 5009297550715157269 --receiver 0xYourAddress --amount 100000000000000000 --dry-run"
echo ""
echo " # Actual send"
echo " $0 --selector 5009297550715157269 --receiver 0xYourAddress --amount 100000000000000000"
exit 1
;;
esac
done
# Validate required arguments
if [ -z "$SELECTOR" ] || [ -z "$RECEIVER" ] || [ -z "$AMOUNT" ]; then
echo "Error: Missing required arguments"
echo "Usage: $0 --selector <chain-selector> --receiver <address> --amount <wei> [--dry-run]"
exit 1
fi
# Validate required environment variables
if [ -z "${BRIDGE_ADDRESS:-}" ]; then
echo "Error: BRIDGE_ADDRESS not set"
echo "Set it to the bridge contract address:"
echo " export BRIDGE_ADDRESS=\$CCIPWETH9_BRIDGE_CHAIN138"
exit 1
fi
if [ -z "${RPC_URL:-}" ]; then
echo "Error: RPC_URL not set"
exit 1
fi
if [ "$DRY_RUN" = false ] && [ -z "${PRIVATE_KEY:-}" ]; then
echo "Error: PRIVATE_KEY not set (required for actual send)"
exit 1
fi
# Default to LINK token if FEE_TOKEN not set
FEE_TOKEN="${FEE_TOKEN:-${LINK_TOKEN:-0x0000000000000000000000000000000000000000}}"
# Validate cast is available
if ! cast --version &>/dev/null; then
echo "Error: cast (Foundry) not found. Please install Foundry:"
echo " curl -L https://foundry.paradigm.xyz | bash"
exit 1
fi
BRIDGE_ADDRESS=$(cast --to-checksum-address "$BRIDGE_ADDRESS")
RECEIVER=$(cast --to-checksum-address "$RECEIVER")
echo "=========================================="
if [ "$DRY_RUN" = true ]; then
echo "CCIP Send (DRY RUN)"
else
echo "CCIP Send"
fi
echo "=========================================="
echo "Bridge Address: $BRIDGE_ADDRESS"
echo "Chain Selector: $SELECTOR"
echo "Receiver: $RECEIVER"
echo "Amount: $AMOUNT wei"
echo "Fee Token: $FEE_TOKEN"
echo ""
# Estimate fee first
echo "Estimating fee..."
FEE=$(cast call "$BRIDGE_ADDRESS" \
"estimateCcipFee(uint64,address,uint256)(uint256)" \
"$SELECTOR" \
"$RECEIVER" \
"$AMOUNT" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "0")
if [ "$FEE" = "0" ] || [ -z "$FEE" ]; then
echo "⚠ Warning: Could not estimate fee. Proceeding anyway..."
FEE="0"
else
FEE_DECIMAL=$(cast --to-dec "$FEE" 2>/dev/null || echo "$FEE")
echo "Estimated fee: $FEE wei ($FEE_DECIMAL)"
fi
# Check sender balance and approval
if [ "$DRY_RUN" = false ]; then
SENDER_ADDRESS=$(cast wallet address --private-key "$PRIVATE_KEY" 2>/dev/null || echo "")
if [ -z "$SENDER_ADDRESS" ]; then
echo "Error: Could not derive address from private key"
exit 1
fi
echo ""
echo "Checking sender balance and approvals..."
echo "Sender: $SENDER_ADDRESS"
# Determine which token (WETH9 or WETH10) based on bridge address
# This is a heuristic - you may need to adjust based on your setup
if [[ "$BRIDGE_ADDRESS" == *"WETH9"* ]] || [[ "${BRIDGE_ADDRESS:-}" == "${CCIPWETH9_BRIDGE_CHAIN138:-}" ]] || [[ "${BRIDGE_ADDRESS:-}" == "${CCIPWETH9_BRIDGE_MAINNET:-}" ]]; then
TOKEN_ADDRESS="${WETH9_ADDRESS:-0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2}"
TOKEN_NAME="WETH9"
else
TOKEN_ADDRESS="${WETH10_ADDRESS:-0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9f}"
TOKEN_NAME="WETH10"
fi
# Check token balance
BALANCE=$(cast call "$TOKEN_ADDRESS" \
"balanceOf(address)(uint256)" \
"$SENDER_ADDRESS" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "0")
if [ "$(cast --to-dec "$BALANCE" 2>/dev/null || echo "0")" -lt "$(cast --to-dec "$AMOUNT" 2>/dev/null || echo "0")" ]; then
echo "⚠ Warning: Insufficient $TOKEN_NAME balance"
echo " Required: $AMOUNT wei"
echo " Available: $BALANCE wei"
else
echo "✓ Sufficient $TOKEN_NAME balance"
fi
# Check approval
ALLOWANCE=$(cast call "$TOKEN_ADDRESS" \
"allowance(address,address)(uint256)" \
"$SENDER_ADDRESS" \
"$BRIDGE_ADDRESS" \
--rpc-url "$RPC_URL" 2>/dev/null || echo "0")
if [ "$(cast --to-dec "$ALLOWANCE" 2>/dev/null || echo "0")" -lt "$(cast --to-dec "$AMOUNT" 2>/dev/null || echo "0")" ]; then
echo "⚠ Warning: Insufficient approval"
echo " Required: $AMOUNT wei"
echo " Approved: $ALLOWANCE wei"
echo ""
echo "Approve the bridge to spend tokens:"
echo " cast send $TOKEN_ADDRESS \\"
echo " \"approve(address,uint256)(bool)\" \\"
echo " $BRIDGE_ADDRESS $AMOUNT \\"
echo " --private-key \$PRIVATE_KEY \\"
echo " --rpc-url \$RPC_URL"
if [ "$DRY_RUN" = false ]; then
read -p "Continue anyway? [y/N]: " confirm
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
echo "Aborted. Please approve first."
exit 1
fi
fi
else
echo "✓ Sufficient approval"
fi
fi
echo ""
if [ "$DRY_RUN" = true ]; then
echo "DRY RUN: Simulating bridgeOut call..."
cast call "$BRIDGE_ADDRESS" \
"bridgeOut(uint64,address,uint256,address)(bytes32)" \
"$SELECTOR" \
"$RECEIVER" \
"$AMOUNT" \
"$FEE_TOKEN" \
--rpc-url "$RPC_URL" || {
echo "Error: Dry run failed"
exit 1
}
echo "✓ Dry run successful (transaction would succeed)"
else
echo "Sending transaction..."
# Determine value to send (if using native fees)
VALUE="0"
if [ "$FEE_TOKEN" = "0x0000000000000000000000000000000000000000" ]; then
VALUE="$FEE"
fi
TX_HASH=$(cast send "$BRIDGE_ADDRESS" \
"bridgeOut(uint64,address,uint256,address)(bytes32)" \
"$SELECTOR" \
"$RECEIVER" \
"$AMOUNT" \
"$FEE_TOKEN" \
--private-key "$PRIVATE_KEY" \
--rpc-url "$RPC_URL" \
--value "$VALUE" \
--gas-limit 500000 2>&1 | grep -oP '0x[a-fA-F0-9]{64}' || echo "")
if [ -z "$TX_HASH" ]; then
echo "Error: Transaction failed or hash not found"
exit 1
fi
echo "✓ Transaction sent!"
echo " Transaction Hash: $TX_HASH"
echo ""
echo "Waiting for confirmation..."
sleep 5
# Try to get receipt
RECEIPT=$(cast receipt "$TX_HASH" --rpc-url "$RPC_URL" 2>/dev/null || echo "")
if [ -n "$RECEIPT" ]; then
echo "✓ Transaction confirmed"
else
echo "⚠ Transaction may still be pending. Check with:"
echo " cast receipt $TX_HASH --rpc-url $RPC_URL"
fi
fi
echo ""
echo "=========================================="
echo "Complete"
echo "=========================================="