Transaction flows
Every state change follows the same pattern: prepare, sign, relay.
- Prepare. Your app calls
POST …/prepare. It returns{ transactions: [ { payload: { xdr } } ] }, an unsigned Stellar transaction. - Sign. The customer signs the authorisation entries with their passkey, on their own device. The private key never leaves it.
- Relay. Your app calls
POST /api/v2/transactions/relaywith{ chain, xdr }. The relayer checks that the call is on the allowlist and authorised by the customer's wallet. - Submit. BlockFinaX submits it to Stellar through OpenZeppelin Channels, with a BlockFinaX fee account as fallback, and returns
{ state, hash }to your app.
Buying protection
POST /api/v2/quotesreturns aProtectionQuote: economic terms plus an executable payload signed with the pricing key.POST /api/v2/hedges/preparewith the quote returns thebuy_protectiontransaction.- The client signs and relays it.
- On chain,
buy_protection:- requires the hedger's authorisation;
- rejects if
now > deadline, the pool is not accepting, notional < 10, or the tenor is not active; - checks the terms against the pool's structures and limits;
- checks the quote is fresh (
now − quote_timestamp ≤ 120), its nonce unused, and its ed25519 signature; - computes the reserve and selects backers; rejects if their free money is short;
- computes premium and fee; rejects if
total > max_cost; - splits the reserve and net premium between backers, records funders, books fees, transfers
premium + feefrom the hedger; - emits
ProtectionPurchased.
Settlement
- After expiry, operators call
submit_rateon the oracle with the position id and expiry. - When enough fresh rates agree, the oracle records the consensus.
- Anyone calls
settle_position(position_id). It readsget_consensus, checks the expiry and band, computes the payout, charges funders, releases reserves, emitsPositionSettled. - The hedger calls
claim_payout(viaPOST /api/v2/hedges/:ref/claim/prepare).
Underwriting
| Action | Prepare endpoint | Contract call |
|---|---|---|
| Deposit | POST /api/v2/pools/:ref/deposits/prepare | deposit |
| Preferences | POST /api/v2/pools/:ref/preferences/prepare | set_lp_preferences |
| Request withdrawal | POST /api/v2/pools/:ref/withdrawals/prepare | request_withdrawal |
| Complete withdrawal | POST /api/v2/withdrawals/:chain/:id/execute/prepare | execute_withdrawal |
Funding from an EVM network
Each user has a personal deposit address on each EVM funding network: an EIP-1167 clone of StellarDeposit, created by StellarDepositFactory with CREATE2 and salt keccak256(stellarWallet). The address is known before it exists and is bound to that wallet.
- The user (or their exchange) sends USDC to the deposit address.
- BlockFinaX reads the canonical USDC balance of every deposit address. It never acts on transfer events, so fake tokens and spoofed logs are ignored.
- For a balance at or above the minimum, BlockFinaX calls
factory.flush(stellarWallet, maxFee, 1000)from a sponsored platform account. The contract burns exactly its USDC throughTokenMessengerV2.depositForBurnWithHook, with Circle's StellarCctpForwarderas recipient and the user's wallet in the hook. The fee is capped on chain at 0.1%. - BlockFinaX reads Circle's attestation and calls
CctpForwarder.mint_and_forwardon Stellar. The user is credited only by this mint.
Anyone may call flush; it can only send the address's own USDC to its own wallet.
Withdrawing to an EVM network
POST /api/v2/routing/executewithkind: "withdraw"returns a USDCapprovefor Circle'sTokenMessengerMinter(markedcontinues).- After it confirms,
POST /api/v2/routing/:id/continuereturnsdeposit_for_burn_with_hook, with Circle's Forwarding Service hook. - Circle attests the burn and submits the mint on the EVM network. BlockFinaX confirms delivery from
MessageTransmitterV2.usedNonces.