This release bumps aleo-sdk, aleo-contract-abi-generator, and shield-swap-sdk to 0.5.0. The big items are a move to snarkVM 4.9.1, mainnet support in shield-swap-sdk, and catching up with the September changes to the Shield Swap API. There are a number of breaking changes in shield-swap-sdk, so read that section before upgrading.
pip install aleo-sdk==0.5.0
pip install aleo-contract-abi-generator==0.5.0
pip install "shield-swap-sdk[async,mcp]==0.5.0"
aleo-sdk
The SDK now builds against snarkVM 4.9.1 from crates.io instead of the v4.8.1 git tag. This picks up consensus versions V18 and V19, which changed how deployments are priced. Previously the bindings hard-coded V17 for cost estimates, which would have underpriced deployments on both live networks. Now execution_cost, deployment_cost, verify_execution, and verify_fee look up the right consensus version from the network's activation table. They take an optional block_height if you want to price against a specific height, and the facade passes the chain head automatically when estimating fees.
The default API host is now https://edge.provable.com/api. It doesn't need an API key, consumer ID, or JWT for reads, the delegated prover, or the hosted record scanner. If you're on api.provable.com with credentials, nothing changes for you.
There's a new Deployment type, with Process.deploy and Process.deployment_cost to go with it.
The two credits conversion helpers, credits_to_microcredits and microcredits_to_credits, used to go through floating point and lose money on the way. 1.005 credits came out as 1,004,999 microcredits, for example. They now use Decimal and are exact. If you pass a value with sub-microcredit precision you'll get a ValueError unless you opt in with allow_rounding=True. from_microcredits returns a Decimal now rather than a float.
Codegen understands fixed-length arrays in ABIs. And most of the public surface that had no docstrings now does.
shield-swap-sdk
Breaking changes
Shield Swap retired a batch of API routes on September 8, so these ApiClient methods are gone: access_status, my_referral_codes, get_tick_spacings, get_swaps, get_swap, get_position, and get_public_balances. Swap and position details are now read from the chain. Tick spacing comes back with the fee tiers. referral_status() tells you whether an account has access and whether the session is alive.
Public balances are chain reads too. ShieldSwap.get_public_balances(programs, address=...) reads each token program's balances mapping directly, and get_balances() has an include_private flag.
Invite codes no longer exist. Signing in is the whole gate. onboard() takes referral_code= instead of invite_code=, and referral codes are optional. NotRedeemedError, redeem_access_code, and generate_access_codes are removed.
The API host is resolved per network. DEFAULT_API_URL is replaced by SHIELD_SWAP_API_URLS and api_url_for(network), and clients pick the host that matches the network they're connected to. SHIELD_SWAP_API_URL still overrides everything.
get_ohlcv takes unix seconds as integers for from_ts and to_ts. It used to accept strings, which the API rejected.
mint() takes a withdrawal address that's stored on the position NFT, and collect() always pays to it. The old recipient argument on collect() is gone.
Amounts are raw token units everywhere. No more 9-decimal normalization or dust rule.
What's new
This is a full cutover from shield_swap_v3.aleo to the deployed shield_swap.aleo. Nothing carries over from v3. The wire layer is regenerated from the deployed bytecode, tick math is Q128.128 with limits pinned from the contract, and freezelist proofs are wired in with empty-tree defaults.
Mainnet works. from_profile() takes network and endpoint, and the API host follows along. The airdrop step is testnet-only, so on mainnet onboard() raises NotFundedError and tells you to fund the account yourself.
Wrapped tokens are handled automatically. Every method checks whether each token is wrapped or plain and routes through the right router entrypoint, so you don't have to know which one to call.
You can now ask what positions you hold and what they're worth without sending a transaction. get_owned_positions() and get_owned_position(token_id) join your private position records with the public pool state and compute amounts and fees owed using the same math the contract uses.
Rebalancing is available on testnet through plan_rebalance and rebalance_position.
swap() is safe to call concurrently. It reserves its blinding counter under the journal lock and writes the claim handle to the journal as soon as the broadcast is accepted, so two swaps in flight can't collide, and a crash mid-swap doesn't lose the claim. Counter reservation also skips past counters already used on chain, so accounts with a lot of history don't hit a scan limit.
A quote failure is now an error rather than a silent fallback to a spot price that ignores the pool fee. That fallback used to produce minimums the pool couldn't pay, which meant paying for a proof that got rejected at finalize. swap_many accepts expected_out if you have your own price source.
get_swap_execution returns the header and per-hop fills for a swap. There are also wrappers for session management (get_session, refresh_session, list_sessions, revoke_session, logout, logout_all), compliance reads, batch pool stats, liquidity distribution, route topology, and referral issuance and reporting. DexApiError exposes the API's error code and ref.
Fixes
increase_liquidity was deriving its tick insert hints from the current slot, which only works for the first position in a pool. Every later call was rejected at finalize after the fee was spent. It now walks the on-chain tick list, the same way mint already did.
The async get_owned_positions wasn't awaiting the record scan and could never have worked.
Profile didn't expand ~, so SHIELD_SWAP_HOME=~/x created a literal ~ directory in the working directory and put the private key there.
Onboarding is idempotent under cookie auth, only reclaims stale tokens that have been idle for a day, and doesn't re-mint on repeated calls when you're at the token cap.
aleo-contract-abi-generator
The Leo crates are pinned to Leo master at c82f149e, which is the first Leo that uses snarkVM 4.9.1. That version of Leo also fixes a bug where record field modes were emitted swapped, so regenerated ABIs now correctly report record owners as private. The generate_abi type stub had three parameters when the function takes four; it's now generated from the Rust signature.
Testing
sdk: 884 unit tests plus the proving and devnode suites. sdk-abi: 8. shield-swap: 351 unit tests, the live read tier against testnet and mainnet, the devnode lifecycle, and the funded testnet write tier, which exercises real swaps and liquidity operations end to end. pyright strict is clean on both Python packages.
Full diff: v0.4.0...v0.5.0