Summary
For TAO->BTC swaps, the protocol checks reserve viability, collateral, min/max bounds, confirm fees, and timeout slash against tao_amount only. The non-TAO destination amount (to_amount) can be arbitrarily large if a miner posts a near-zero TAO/BTC rate.
That means a route can be marked viable and accepted as an exact quote even when it promises an impossible BTC payout. If it times out, the miner's slash is still only the TAO leg, not the BTC payout it advertised.
This is related to #392/#393, but it is a narrower protocol/economic invariant: destination-side payout exposure is not bounded or collateral-backed for reverse swaps.
Live evidence
Current live quote:
uv run alw swap quote --from tao --to btc --amount 0.1
# UID Rate You Receive Collateral Status
1 253 1000 0.00009900 BTC 0.5153 TAO available
2 14 999 0.00009910 BTC 0.5060 TAO available
3 65 340.82 0.00029048 BTC 0.5782 TAO available
4 189 340.32 0.00029091 BTC 0.4792 TAO available
5 193 1e-08 9900000.00000000 BTC 0.5998 TAO available
The UID 193 row says a user sending 0.1 TAO would receive 9,900,000 BTC, and the CLI marks it available because the TAO leg is within bounds and below the miner's TAO collateral.
Local reserve-path proof
Using the same shared math as CLI, validator, and miner:
from_chain=tao
to_chain=btc
from_amount=0.1 TAO
rate=1e-08
collateral=0.5998 TAO
min_swap=0.1 TAO
max_swap=0.5 TAO
Local proof output:
canonical_pair=btc->tao is_reverse=True
send_tao=0.1 rate=1e-08
raw_to_amount_sats=1000000000000000
user_receives_btc=9900000
tao_leg=0.1 collateral_tao=0.5998
check_swap_viability=True reason=ok
quote_within_slippage_exact=True
confirm_fee_tao=0.001
timeout_slash_tao=0.1
promised_btc_to_timeout_slash_ratio=9.900000E+7 BTC_per_TAO_slashed
So the exact reserve quote passes:
quote_within_slippage(to_amount, to_amount, 200) == True
check_swap_viability(0.1 TAO, 0.5998 TAO collateral, 0.1-0.5 TAO bounds) == True
But the destination payout is 9,900,000 BTC.
Code path
The validator reserve path recomputes to_amount from the miner commitment and checks exact/slippage consistency, but the bounds and collateral gates only compare synapse.tao_amount:
allways/validator/axon_handlers.py:366-385
expected_to_amount = recompute_reserve_amounts(...)
expected_tao_amount = derive_tao_leg(...)
if synapse.tao_amount != expected_tao_amount: reject
if not quote_within_slippage(synapse.to_amount, expected_to_amount, slippage_bps): reject
allways/validator/axon_handlers.py:407-422
if synapse.tao_amount > collateral: reject
if synapse.tao_amount < min_swap: reject
if synapse.tao_amount > max_swap: reject
The shared viability helper mirrors the same invariant:
allways/utils/rate.py:122-141
def check_swap_viability(tao_amount_rao, miner_collateral_rao, min_swap_rao, max_swap_rao):
if tao_amount_rao < min_swap_rao: ...
if tao_amount_rao > max_swap_rao: ...
if tao_amount_rao > miner_collateral_rao: ...
return True
The contract stores to_amount, but reserve and initiate also only gate the TAO leg against bounds/collateral:
smart-contracts/ink/lib.rs:574-590
if tao_amount < min_swap_amount: AmountBelowMinimum
if tao_amount > max_swap_amount: AmountAboveMaximum
if miner_collateral < min_collateral: InsufficientCollateral
smart-contracts/ink/lib.rs:855-872
if tao_amount/from_amount/to_amount != reservation: InvalidAmount
if tao_amount > miner_collateral: InsufficientCollateral
On timeout, the slash is also only swap.tao_amount:
smart-contracts/ink/lib.rs:1026-1029
let actual_slash = this.apply_collateral_penalty(swap.miner, swap.tao_amount);
On success, the protocol fee charged to miner collateral is also only based on swap.tao_amount:
smart-contracts/ink/lib.rs:976-982
let fee = swap.tao_amount.saturating_div(FEE_DIVISOR);
let actual_fee = this.apply_collateral_penalty(swap.miner, fee);
Why this matters
For TAO->BTC, a miner can post a tiny TAO/BTC rate that implies an arbitrary BTC payout. The system treats the quote as viable because the user source is a small TAO amount inside the contract bounds.
The miner is never required to collateralize the promised BTC output. If it fails, timeout slash is only the TAO source leg. If it somehow confirms, the fee is only 1% of the TAO source leg.
That is not a safe market invariant. The protocol is treating tao_amount as the universal exposure metric even when the actual user-facing promise is a non-TAO destination amount.
Duplicate check
Raw authenticated GraphQL duplicate sweep checked:
payout collateral
destination collateral
BTC payout collateral
non-TAO destination collateral
TAO->BTC collateral
1e-08
9900000
absurd BTC
economically collateral
collateral-backed
output amount
to_amount collateral
to_amount bounds
destination payout
vote_reserve to_amount
tao_amount/from_amount/to_amount
slash exposure
timeout slash
quote available
expected_to_amount
derive_tao_leg
Closest related items:
No existing open/closed issue or PR was found for non-TAO destination payouts being unbounded relative to collateral/slash exposure.
Expected direction
The protocol needs a direction-aware exposure invariant. Possible fixes:
- Reject non-TAO destination amounts that exceed a sane value derived from miner collateral, current bounds, and/or rate sanity.
- Add a destination-side payout cap for non-TAO outputs.
- Make crown/reserve eligibility require that the posted quote is economically collateral-backed, not only TAO-leg-valid.
- For CLI, do not mark TAO->BTC routes as
available when the destination output is nonsensical relative to collateral/exposure.
The key invariant: a route should not be considered reservable if the miner's maximum penalty is a small TAO amount while the quoted destination payout is effectively unbounded.
Validation
Commands run:
uv run alw swap quote --from tao --to btc --amount 0.1
uv run pytest tests/test_rate.py tests/test_axon_handlers.py -q
Result:
Summary
For TAO->BTC swaps, the protocol checks reserve viability, collateral, min/max bounds, confirm fees, and timeout slash against
tao_amountonly. The non-TAO destination amount (to_amount) can be arbitrarily large if a miner posts a near-zero TAO/BTC rate.That means a route can be marked viable and accepted as an exact quote even when it promises an impossible BTC payout. If it times out, the miner's slash is still only the TAO leg, not the BTC payout it advertised.
This is related to #392/#393, but it is a narrower protocol/economic invariant: destination-side payout exposure is not bounded or collateral-backed for reverse swaps.
Live evidence
Current live quote:
The UID 193 row says a user sending
0.1 TAOwould receive9,900,000 BTC, and the CLI marks itavailablebecause the TAO leg is within bounds and below the miner's TAO collateral.Local reserve-path proof
Using the same shared math as CLI, validator, and miner:
Local proof output:
So the exact reserve quote passes:
quote_within_slippage(to_amount, to_amount, 200) == Truecheck_swap_viability(0.1 TAO, 0.5998 TAO collateral, 0.1-0.5 TAO bounds) == TrueBut the destination payout is
9,900,000 BTC.Code path
The validator reserve path recomputes
to_amountfrom the miner commitment and checks exact/slippage consistency, but the bounds and collateral gates only comparesynapse.tao_amount:The shared viability helper mirrors the same invariant:
The contract stores
to_amount, but reserve and initiate also only gate the TAO leg against bounds/collateral:On timeout, the slash is also only
swap.tao_amount:On success, the protocol fee charged to miner collateral is also only based on
swap.tao_amount:Why this matters
For TAO->BTC, a miner can post a tiny TAO/BTC rate that implies an arbitrary BTC payout. The system treats the quote as viable because the user source is a small TAO amount inside the contract bounds.
The miner is never required to collateralize the promised BTC output. If it fails, timeout slash is only the TAO source leg. If it somehow confirms, the fee is only 1% of the TAO source leg.
That is not a safe market invariant. The protocol is treating
tao_amountas the universal exposure metric even when the actual user-facing promise is a non-TAO destination amount.Duplicate check
Raw authenticated GraphQL duplicate sweep checked:
Closest related items:
swap quoteroute display and sorting. This draft is not just CLI display; the validator and contract reserve paths use the same TAO-leg-only exposure invariant.swap nowand crown selection; they do not bound destination-side payout exposure.No existing open/closed issue or PR was found for non-TAO destination payouts being unbounded relative to collateral/slash exposure.
Expected direction
The protocol needs a direction-aware exposure invariant. Possible fixes:
availablewhen the destination output is nonsensical relative to collateral/exposure.The key invariant: a route should not be considered reservable if the miner's maximum penalty is a small TAO amount while the quoted destination payout is effectively unbounded.
Validation
Commands run:
Result: