This document describes how the Credence bond contract integrates with Stellar token contracts for USDC-denominated bonds.
The bond contract uses Soroban token interfaces for all value movements:
initialize(admin, token)stores the custody token contract address.create_bondandtop_upmove tokens from identity to contract withtransfer_from.withdrawmoves tokens from contract to the bonded identity withtransfer.withdraw_earlymoves net proceeds to the bonded identity and the penalty to treasury withtransfer.
initialize(admin, token)- Stores the custody token during contract setup.
get_token()- Returns the currently configured token address.
Token handling is centralized in contracts/credence_bond/src/token_integration.rs with the following controls:
- Admin-gated token configuration
- Only stored admin can set token address.
- Allowance pre-checks
- Before
transfer_from, contract checksallowance(owner, contract). - If allowance is insufficient, call fails with
insufficient token allowance.
- Before
- Positive amount validation
create_bond,top_up,withdraw, andwithdraw_earlyrejectamount <= 0.
- Checks-effects-interactions
- Exit paths persist the reduced bond state before transferring tokens out.
- Single integration layer
- Prevents duplicated transfer logic and keeps security review surface small.
- Admin initializes the contract with a valid token contract address.
- Identity accounts grant approvals to the bond contract before
create_bondandtop_up. - Token contract adheres to Soroban token interface semantics.
Root custody tests cover:
- Token configuration and retrieval.
- Successful token movement into contract during
create_bond. - Failure on missing allowance for
create_bond. - Failure when
top_upexceeds remaining allowance. - Successful token movement back to identity on
withdraw. - Treasury and identity routing during
withdraw_early.
Run targeted tests:
cargo test -p credence_bond token_integration_test -- --nocaptureRun full package tests:
cargo test -p credence_bond -- --nocaptureFor unslashed flows, contract token custody should match the withdrawable bond amount:
token.balance(bond_contract) == bonded_amount - slashed_amount
See bond-token-custody.md for the current scope and the remaining slash-path gap.