Files
proxmox/scripts/deployment/price-cw-token-mainnet.sh
defiQUG b8613905bd
Some checks failed
Deploy to Phoenix / validate (push) Failing after 15s
Deploy to Phoenix / deploy (push) Has been skipped
chore: sync workspace — configs, docs, scripts, CI, pnpm, submodules
- Submodule pins: dbis_core, cross-chain-pmm-lps, mcp-proxmox (local, push may be pending), metamask-integration, smom-dbis-138
- Atomic swap + cross-chain-pmm-lops-publish, deploy-portal workflow, phoenix deploy-targets, routing/aggregator matrices
- Docs, token-lists, forge proxy, phoenix API, runbooks, verify scripts

Made-with: Cursor
2026-04-21 22:01:33 -07:00

192 lines
7.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# Price cW* wrapped stables on Ethereum Mainnet using:
# (1) Accounting peg assumption ($1 per token for USD-stable wrappers — document in reporting)
# (2) DODO PMM integration: getPoolPrice / getPoolPriceOrOracle (1e18 = $1 when oracle aligned)
# (3) Implied ratio from pool vault reserves (USDC per cWUSDT if base/quote match manifest)
# (4) Optional Chainlink ETH/USD (macro reference only; not cW* direct)
#
# Usage (from repo root):
# source scripts/lib/load-project-env.sh
# ./scripts/deployment/price-cw-token-mainnet.sh
# ./scripts/deployment/price-cw-token-mainnet.sh --json
# POOL_CWUSDT_USDC_MAINNET=0x... ./scripts/deployment/price-cw-token-mainnet.sh
#
# Requires: cast (Foundry), jq (for --json)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# shellcheck disable=SC1091
[[ -f "$PROJECT_ROOT/scripts/lib/load-project-env.sh" ]] && source "$PROJECT_ROOT/scripts/lib/load-project-env.sh"
JSON=false
for a in "$@"; do [[ "$a" == "--json" ]] && JSON=true; done
RPC="${ETHEREUM_MAINNET_RPC:-https://ethereum-rpc.publicnode.com}"
INT="${DODO_PMM_INTEGRATION_MAINNET:-0xa9F284eD010f4F7d7F8F201742b49b9f58e29b84}"
CWUSDT="${CWUSDT_MAINNET:-0xaF5017d0163ecb99D9B5D94e3b4D7b09Af44D8AE}"
# Mainnet canonical USDC (do not use Chain 138 OFFICIAL_USDC_ADDRESS for this script)
USDC_MAINNET_CANON="${USDC_MAINNET:-0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48}"
USDC_OFFICIAL="${USDC_MAINNET_CANON}"
POOL="${POOL_CWUSDT_USDC_MAINNET:-0x27f3aE7EE71Be3d77bAf17d4435cF8B895DD25D2}"
# Chainlink ETH/USD — verified on mainnet; optional macro reference
CHAINLINK_ETH_USD="${CHAINLINK_ETH_USD_FEED:-0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419}"
first_word() {
awk '{print $1}' | head -1
}
to_dec() {
local x="$1"
[[ -z "$x" ]] && echo "" && return
echo "$x" | sed 's/\[.*//g' | awk '{print $1}'
}
get_decimals() {
local tok="$1"
to_dec "$(cast call "$tok" "decimals()(uint8)" --rpc-url "$RPC" 2>/dev/null || echo "")"
}
price_oracle_or_mid() {
local pool="$1"
local out
out=$(cast call "$INT" "getPoolPriceOrOracle(address)(uint256)" "$pool" --rpc-url "$RPC" 2>/dev/null | first_word) || true
if [[ -n "$out" && "$out" != *Error* ]]; then
printf '%s|%s\n' "getPoolPriceOrOracle" "$out"
return
fi
out=$(cast call "$INT" "getPoolPrice(address)(uint256)" "$pool" --rpc-url "$RPC" 2>/dev/null | first_word) || true
printf '%s|%s\n' "getPoolPrice" "$out"
}
parse_two_uints() {
python3 -c "
import re, sys
s = sys.stdin.read()
# cast may print scientific notation for large numbers
parts = re.findall(r'-?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?', s)
if len(parts) >= 2:
print(int(float(parts[0])), int(float(parts[1])))
"
}
reserves() {
local pool="$1"
cast call "$INT" "getPoolReserves(address)(uint256,uint256)" "$pool" --rpc-url "$RPC" 2>/dev/null | parse_two_uints
}
eth_usd_chainlink() {
local feed="$1"
[[ -z "$feed" ]] && { echo ""; return; }
local code
code=$(cast code "$feed" --rpc-url "$RPC" 2>/dev/null || true)
[[ -z "$code" || "$code" == "0x" ]] && { echo ""; return; }
cast call "$feed" "latestRoundData()(uint80,int256,uint256,uint256,uint80)" --rpc-url "$RPC" 2>/dev/null
}
db=$(get_decimals "$CWUSDT")
dq=$(get_decimals "$USDC_OFFICIAL")
read -r br_raw qr_raw < <(reserves "$POOL" | awk '{print $1, $2}')
br_raw=$(to_dec "${br_raw:-0}")
qr_raw=$(to_dec "${qr_raw:-0}")
_pom=$(price_oracle_or_mid "$POOL")
pm_method="${_pom%%|*}"
price_raw=$(to_dec "${_pom#*|}")
# price from integration is 1e18-scaled "USD" in docs
price_human=""
if [[ -n "$price_raw" && "$price_raw" =~ ^[0-9]+$ ]]; then
price_human=$(python3 -c "print(int('$price_raw')/1e18)" 2>/dev/null || echo "")
fi
implied_usdc_per_cwusdt=""
if [[ -n "$br_raw" && -n "$qr_raw" && "$br_raw" != "0" && -n "$db" && -n "$dq" ]]; then
implied_usdc_per_cwusdt=$(python3 -c "br=int('$br_raw'); qr=int('$qr_raw'); db=int('$db'); dq=int('$dq'); print((qr/10**dq)/(br/10**db))" 2>/dev/null || echo "")
fi
cl_eth=$(eth_usd_chainlink "$CHAINLINK_ETH_USD")
cl_eth_price=""
if [[ -n "$cl_eth" ]]; then
# latestRoundData(): cast prints one value per line; answer is the 2nd field (int256, 1e8 USD for ETH/USD)
ans=$(echo "$cl_eth" | awk 'NR == 2 { print $1; exit }')
[[ -n "$ans" ]] && cl_eth_price=$(python3 -c "a=int(float('$ans')); print(a/1e8)" 2>/dev/null || echo "")
fi
if [[ "$JSON" == true ]]; then
jq_n() { [[ -z "$1" ]] && echo null || echo "$1"; }
jq -n \
--arg network "ethereum-mainnet" \
--arg token "cWUSDT" \
--arg token_addr "$CWUSDT" \
--arg pool "$POOL" \
--arg integration "$INT" \
--argjson accounting_usd_assumption 1 \
--arg pool_price_method "${pm_method:-none}" \
--argjson pool_price_raw "$(jq_n "$price_raw")" \
--argjson pool_price_usd_scale "$(jq_n "$price_human")" \
--argjson base_reserve_raw "$(jq_n "$br_raw")" \
--argjson quote_reserve_raw "$(jq_n "$qr_raw")" \
--arg implied_str "${implied_usdc_per_cwusdt:-}" \
--argjson chainlink_eth_usd "$(jq_n "$cl_eth_price")" \
'{
network: $network,
token: $token,
tokenAddress: $token_addr,
poolAddress: $pool,
integrationAddress: $integration,
accountingUsdAssumptionPerToken: $accounting_usd_assumption,
poolMidOrOracle: {
method: $pool_price_method,
priceRaw1e18: $pool_price_raw,
priceAsUsdIf1e18EqualsOneDollar: $pool_price_usd_scale
},
impliedFromReserves: {
baseReserveRaw: $base_reserve_raw,
quoteReserveRaw: $quote_reserve_raw,
impliedUsdcPerCwusdtIfBaseIsCwusdtAndQuoteIsUsdc: (if $implied_str == "" then null else ($implied_str | tonumber) end)
},
chainlinkEthUsd: $chainlink_eth_usd
}'
exit 0
fi
cat << EOF
========================================
cWUSDT (Mainnet) — USD pricing toolkit
========================================
RPC: ${RPC%%\?*}
Integration: $INT
Pool (cWUSDT/USDC): $POOL
cWUSDT token: $CWUSDT
USDC (mainnet): $USDC_OFFICIAL
(1) ACCOUNTING ASSUMPTION (treasury / reporting)
Treat 1 cWUSDT ≈ 1 USD only if your policy says the wrapper tracks USDT 1:1.
Use for: internal books, dashboards where Etherscan shows \$0.
(2) POOL MID / ORACLE (DODOPMMIntegration)
Method: ${pm_method:-n/a}
Raw price (uint256, doc scale 1e18 = \$1): ${price_raw:-n/a}
As decimal (if 1e18 = \$1): ${price_human:-n/a}
(3) IMPLIED FROM VAULT RESERVES (USDC per cWUSDT)
Base reserve (cWUSDT, ${db:-?} dp): ${br_raw:-n/a}
Quote reserve (USDC, ${dq:-?} dp): ${qr_raw:-n/a}
Implied USDC per 1 cWUSDT: ${implied_usdc_per_cwusdt:-n/a}
(Thin or imbalanced pools skew this; use for sanity check, not sole mark.)
(4) CHAINLINK ETH/USD (macro only — not cWUSDT)
Feed: ${CHAINLINK_ETH_USD}
ETH/USD: ${cl_eth_price:-n/a}
Optional env overrides:
ETHEREUM_MAINNET_RPC, DODO_PMM_INTEGRATION_MAINNET,
CWUSDT_MAINNET, POOL_CWUSDT_USDC_MAINNET, USDC_MAINNET,
CHAINLINK_ETH_USD_FEED
See: docs/03-deployment/CW_TOKEN_USD_PRICING_RUNBOOK.md
========================================
EOF