Escrow object, created when the package is published, holds the deposit float, the referral voucher float, the settlement marker table, and the redeemed voucher table. Deposits pay into the escrow and refunds pay out of it; fulfillments are paid by the treasury address from its own balance, with the package allowing each quote hash to be filled at most once while its settlement marker exists, and emitting the events the indexer reads.
Prefer the
router_address (package id) returned on the quote and the escrow, treasury, and swap_executor returned by GetChains over these constants. All functions live in module blink and take the coin type as a type argument. Native USDC is the bridge token; other coins enter through source swap intents and leave through swap fills.
Deposit
T and emits Deposit with the amount and sender. The quote hash must be exactly 32 bytes.
There is no swap-first deposit function: an aggregator route run in the depositor’s own transaction block would run every route command with the depositor as sender. Swap-first deposits open a source swap intent instead.
Source swaps
0x2::allowance::propose_for_app<Balance<In>, SourceSwapFunding>. The proposal must name the escrow’s swap executor as spender (otherwise EUnauthorized), carry a lifetime cap, which becomes the source amount, and an expiration no more than five minutes after the clock, and have no start time and no rate limit (otherwise EInvalidSourceSwap). The resulting allowance draws from the depositor’s address balance and can only be spent through begin_source_swap. The function shares a SourceSwapIntent<In, Out> holding the quote hash, the depositor as funder, the source amount, min_lock_amount, and the expiration, and emits SourceSwapOpened.
begin_source_swap aborts with EUnauthorized unless the sender is the escrow’s swap executor and the gas owner is the source swap sponsor set with set_source_swap_sponsor, deletes the intent, aborts with ESourceSwapExpired once the intent has expired, and draws exactly the source amount from the funder’s allowance. The allowance must be the one the intent opened: same funder, a lifetime cap of exactly the source amount, the intent’s expiration, and nothing spent yet (otherwise EInvalidSourceSwap). Its SourceSwap result has no abilities, so the same block must pass it to finish_source_swap after the aggregator route has turned the coin into Out. finish_source_swap aborts with EInsufficientOutput below min_lock_amount, joins the coin into the escrow, and emits SwapDeposit with the funder as from and the source coin type and amount from the intent. Deleting the intent makes each intent run at most once.
Operator functions
Restricted to the treasury, or for swap fills to the swap executor in a transaction the treasury sponsors, listed for completeness.fulfill transfers the payout coin and, when nonzero, the SUI gas drop coin to the recipient. fulfill_swap is used when the recipient asked for a coin other than the bridge token: the swap executor draws bridge float from the treasury’s address balance with draw_swap_funds, swaps it through an aggregator route earlier in the same transaction block, and passes the output here. draw_swap_funds and fulfill_swap run only when the sender is the swap executor and the treasury sponsors the transaction; draw_swap_funds spends a treasury allowance bound to the package, and the gas drop is drawn the same way. It aborts with EInsufficientOutput when the swap output is below min_amount_out, pays the recipient the smaller of the swap output and expected_amount_out, returns any surplus to the treasury, sends the gas drop like fulfill, and emits SwapFulfilled. refund pays the recipient out of the escrow’s deposit balance. fulfill and fulfill_swap insert a settlement marker keyed by the quote hash and abort if one already exists. refund aborts with EQuoteFilled if the quote hash already has a marker and inserts a marker keyed by the deposit digest and ordinal it is given; it does not mark the quote hash, and the package does not check the digest and ordinal against a real deposit. Because the swap and the marker live in one transaction block, a fulfill_swap that aborts on the marker reverts its swap too. release_with_vouchers takes amount of settled deposit float out of the escrow, credits voucher_amount of it to the voucher float, and sends the rest to the treasury; it aborts when voucher_amount is larger than amount. The operator sets voucher_amount to the referrer share of the fulfilled deposits in the release, and the signer cluster recomputes it from each deposit’s quote before signing. release is the same call with no voucher share, kept so package upgrades stay compatible; the signer cluster only signs release_with_vouchers.
Settlement markers and pruning
Each marker stores the epoch it was settled in. Markers are the on-chain replay guard, and because every operator transaction also carries an expiration epoch, a marker older than the retention window can be safely removed to reclaim its storage rebate:prune is permissionless and aborts with ERetentionNotElapsed until 180 epochs (about six months) have passed since settlement. The storage rebate is credited to the pruning transaction.
Voucher redemption
Referral fees accrue off-chain and are paid on Sui through signed vouchers, redeemed by the referrer’s own wallet against a voucher float held inside the escrow. Releases fill the float with the referrer share of each fulfilled deposit:
Voucher ids are marked in a permanent table, so each voucher redeems exactly once. Vouchers never expire, and the redeemed-id table is never pruned.
fund_vouchers is permissionless and tops the float up by hand; defund_vouchers returns float to the treasury.
Admin
issue_swap_allowance is called by the treasury with a proposal from 0x2::allowance::propose_for_app<Balance<C>, SwapFunding> naming the swap executor as spender; the resulting allowance can only be spent through draw_swap_funds. set_source_swap_sponsor names the gasless sponsor address that must pay for every source swap; until it is set, no source swap can run. The AdminCap is transferred to the treasury at deploy time. Voucher signers are append-only: rotating the key adds the new one, and vouchers signed by earlier keys stay redeemable.
The escrow records the package version it serves. Every function that takes the escrow, other than migrate, aborts with EWrongVersion unless the escrow’s version equals the version of the package being called, so after an upgrade that raises the version and a call to migrate, earlier package versions can no longer act on the escrow. migrate raises the escrow to the called package’s version and aborts with ENotUpgrade when the escrow is already at that version or a later one.
Events
coin_type and src_coin_type are full coin type strings of the type arguments, without a 0x prefix. In SwapDeposit, amount is the bridge amount that landed in the escrow. In SwapFulfilled, amount is what the recipient received and swap_out is the full swap output, so the surplus returned to the treasury is swap_out - amount.
Event type names carry the id of the package version that first defined the type, so after an upgrade newer events carry a newer id than older ones. Match events on any version’s id. In SourceSwapOpened, coin_type is the bridge coin the intent swaps into and expires_at_ms is when the intent and its allowance expire.