T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/_common.sh:147
- Finding
- Unsafe Token Amount Conversion Can Produce Incorrect On-Chain Values## Vulnerability Details **File Location**: `scripts/_common.sh`, lines 147-167 **Vulnerability Type**: Inaccurate financial amount conversion **Risk Level**: High The shared conversion helpers use binary floating-point arithmetic and assume that every unknown token has six decimal places: ```bash # Convert human-readable amount to raw token units (e.g. 50 → 50000000 for 6-decimal USDC) to_wei() { local amount="$1" local decimals="${2:-6}" assert_decimal "amount" "$amount" assert_uint "decimals" "$decimals" python3 -c "print(int(float($amount) * 10**$decimals))" 2>/dev/null || echo "$amount" } # Alias: convert raw units back to human-readable (same as format_amount) to_token_units() { format_amount "$1" "${2:-6}" } # Resolve token symbol → decimals token_decimals() { local sym="${1,,}" case "$sym" in usdc) echo "6" ;; *) echo "6" ;; # default to 6 for stablecoins esac } ``` The vulnerable helpers are used for irreversible financial operations, including: ```bash # scripts/deai-approve-token.sh:22 AMOUNT_WEI=$(to_wei "$AMOUNT") # scripts/deai-bid.sh:20 AMOUNT_RAW=$(to_wei "$AMOUNT") # scripts/deai-create-auction.sh:50 RESERVE_RAW=$(to_wei "$RESERVE_PRICE" "$(token_decimals "$PAYMENT_TOKEN")") ``` ### Technical Analysis `float()` uses IEEE-754 binary floating-point representation. Decimal token quantities generally cannot be represented exactly, and integers beyond the exact precision range of a double can be rounded. The subsequent `int()` operation silently truncates the computed value. Consequently, the raw integer submitted to the smart contract may differ from the amount entered by the user. This is unsafe for cryptocurrency transactions, where amounts must be converted with exact decimal arithmetic. The conversion can affect approvals, bids, and auction reserve prices. The second issue is the unconditional six-decimal fallback in `token_deci ...[truncated 2682 chars]
- Remediation
- ## Remediation Suggestions 1. Replace binary floating-point conversion with exact decimal or integer-string arithmetic. For example, use Python's `decimal.Decimal` with strict validation: ```bash to_wei() { local amount="$1" local decimals="$2" assert_decimal "amount" "$amount" assert_uint "decimals" "$decimals" python3 - "$amount" "$decimals" <<'PY' from decimal import Decimal, InvalidOperation import sys amount_text = sys.argv[1] decimals = int(sys.argv[2]) try: amount = Decimal(amount_text) except InvalidOperation: raise SystemExit("Invalid decimal amount") if amount < 0: raise SystemExit("Amount cannot be negative") scale = Decimal(10) ** decimals raw = amount * scale if raw != raw.to_integral_value(): raise SystemExit( f"Amount has more than {decimals} fractional decimal places" ) print(int(raw)) PY } ``` 2. Remove the six-decimal fallback for arbitrary token addresses. Query the token contract before conversion: ```bash decimals=$(cast call "$TOKEN_ADDR" "decimals()(uint8)" \ --rpc-url "$DEAI_RPC_URL") ``` Validate that the result is an integer within a reasonable ERC-20 range before using it. 3. Keep a six-decimal constant only for the specifically verified Base USDC contract address. Do not infer precision merely from an untrusted symbol string. 4. Remove the fail-open `|| echo "$amount"` behavior. Conversion errors must terminate the script before transaction signing. 5. Validate conversions by performing an exact round trip from the generated raw integer back to the original decimal representation. 6. Before signing, show the token address, queried decimals, exact raw amount, and normalized human-readable amount, then require explicit confirmation for auctions, approvals, bids, and purchases. 7. Add tests covering zero-d ...[truncated 184 chars]
