ERC-1155 balanceOf calldata encoding/decoding + eth_call glue for autotrade on-chain CTF reconciliation. Lives in crates/polymarket-fetch/src/pmv2/autotrade/onchain.rs.
What Was Built
ctf_balance_of(proxy_wallet, token_id, rpc_url) — an async function that encodes an ERC-1155 balanceOf(address,uint256) calldata, fires an eth_call RPC request, and decodes the returned uint256 balance. Pure build-verification only (not tested via network); three unit tests cover encode, decode, and bad-address rejection.
Files Changed
| File | Change |
|---|---|
crates/polymarket-fetch/Cargo.toml | Added alloy-sol-types and alloy-primitives as workspace deps |
crates/polymarket-fetch/src/config.rs | Added polygon_rpc_url: String field + POLYGON_RPC_URL env load |
crates/polymarket-fetch/src/pmv2/autotrade/mod.rs | Added pub mod onchain; |
crates/polymarket-fetch/src/pmv2/autotrade/onchain.rs | CREATED — ERC-1155 calldata encode/decode + eth_call glue |
Alloy sol! Struct Name Generation
sol! macro generates a struct named balanceOfCall — camelCase function name + Call suffix — for balanceOf(address,uint256). The right encoding method is SolCall::abi_encode(), not any manual packing.
use alloy_sol_types::SolCall;
let call = balanceOfCall { account: proxy, id: token_id };
let calldata = call.abi_encode();For Agents
The
Callsuffix is consistent across allsol!-generated function structs. If the function isfooBar(uint256)the type isfooBarCall. UseSolCall::abi_encode()for the calldata bytes.
alloy_primitives::hex Re-Export
alloy-primitives re-exports a hex module directly — no separate hex crate needed.
use alloy_primitives::hex;
let hex_str = hex::encode(&calldata); // lowercase, no 0x prefixThe RPC eth_call data field requires a "0x" prefix — prepend manually: format!("0x{}", hex::encode(...)).
Selector Verification
balanceOf(address,uint256) selector is 0x00fdd58e — the ERC-1155 standard.
Different from ERC-20
ERC-20
balanceOf(address)selector is0x70a08231. These are completely different functions. The CTF contract is ERC-1155, so0x00fdd58eis always correct here.
Spike Doc Value Error — pUSD Balance
The spike findings doc (docs/superpowers/specs/2026-06-14-pmv2-autotrade-spike-findings.md) contains an error in the hex-to-decimal conversion table:
| Field | Spike Doc Says | Correct Value |
|---|---|---|
| Hex | 0x2c641ab6 | 0x2c641ab6 |
| Decimal | 744144054 | 744757942 |
| pUSD amount | 744.144054 pUSD | 744.757942 pUSD |
The plan spec test originally used 744_144_054u128 — this is wrong. The actual unit test uses 744_757_942u128. The narrative “Bandi 744 pUSD” is an approximation; the exact on-chain raw value should be verified against a live RPC call in Task 7 preflight.
Verify in Task 7
744_757_942is the corrected decode of0x2c641ab6but the live balance will have changed since the spike. Task 7 preflight must fire a liveeth_calland treat whatever comes back as the ground truth.
Binary-Only Crate: Test Invocation
polymarket-fetch is binary-only — there is no src/lib.rs. Tests cannot be run with --lib.
# WRONG
cargo test --lib -p polymarket-fetch
# CORRECT
cargo test --bin polymarket-fetch -p polymarket-fetch
# or simply
cargo test -p polymarket-fetchConfig Pattern
polygon_rpc_url was added to AppConfig with #[allow(dead_code)] — it is loaded from POLYGON_RPC_URL env, defaulting to https://polygon-rpc.com. The #[allow(dead_code)] suppression will be removed when Task 7 preflight consumes it.
Test Coverage
Three pure unit tests, zero network calls:
- encode —
balanceOf(address,uint256)calldata includes the0x00fdd58eselector prefix - decode —
0x000…002c641ab6decodes to744_757_942u128 - bad-address rejection — a non-checksummed / invalid hex address string returns an
Err
ctf_balance_of itself is #[allow(dead_code)] and build-verified only; it will be tested end-to-end in Task 7.
Gate Result
PASS (exit 0). All 256 tests pass including the 3 new onchain unit tests.
Related
- autotrade-eip712-order-hash — the other alloy primitive in the same phase
- autotrade-clob-crate-bindings — vendored rs-clob-client-v2 bindings
- pmv2-autotrade-engine-design — engine design, incl. on-chain CTF reconciliation as ground truth
- autotrade-persistence-engine-config — persistence layer that the reconciliation will feed