A footprint-minimal coinswap protocol. Alice gives a coin to the Server, provided the Server gives a coin to Bob. There is no trust involved. Because all swaps go through the Server and the timelock eventually expires in their favor, a large number of swaps can be aggregated in a single UTXO that is efficiently on-chain redeemable by them. This comes at the cost of not being able to instantly access their funds, meaning the Server ends up locking up a substantial amount of coins.
All transactions that are involved with A
sending to B
Alice (A
) holds coins with Server (S
) that she can trustlessly redeem
On-chain UTXO_1 looks as follows:
A+S || S in 1 month
A
has an off-chain REDEEM_TX (signed by S) that spends from UTXO_1 with the following output:
A+S || A in 1 month
Now A
wants to send her coins to Bob (B
)
S
promises to fund and create new on-chain UTXO_2 that will look as follows:
B+S || S in 1 month
B
receives an off-chain REDEEM_TX (signed by S) that spends from UTXO_2 with the following output:
B+S || B in 1 month
If UTXO_2 appears on-chain, B
will be paid.
A
wants to forfeit her claim on UTXO_1 (i.e. A
to S
) provided UTXO_2 appears on-chain (i.e. S
to B
)
In order to achieve this, A
signs the following FORFEIT_TX that spends her REDEEM_TX:
S if UTXO_2 exists* || A in 1 month
*This kind of script is not possible today but is easier to explain, actual non-softfork version explained later
The effect is that S
can claim the funds from UTXO_1
if UTXO_2
is published.
Ideal/expected outcome:
S
publishes UTXO_2, meaningB
got paidA
won't publish her REDEEM_TX- The timelock on UTXO_1 expires and
S
claims the funds (timelock could be circumvented ifA
releases her privkey)
Outcome adversarial A
:
S
publishes UTXO_2, meaningB
got paidA
publishes her REDEEM_TXS
publishes the corresponding FORFEIT_TX and claims the funds
Outcome adversarial S
:
S
never publishes UTXO_2, soB
did NOT get paidA
publishes her REDEEM_TXS
publishes the corresponding FORFEIT_TX- The FORFEIT_TX timelock expires and
A
claims the funds
Outcome offline A
:
A
fails to askS
to transfer the funds toB
A
fails to publish her REDEEM_TX in time- The timelock on UTXO_1 expires and
S
claimsA
's funds
The protocol that was described thus far isn't any more efficient than A
simply sending an on-chain payment to B
. The final trick is that a single UTXO can contain coins for multiple users.
UTXO_1 is being shared here by two users and is eventually fully claimable by S
For instance, let's say A
and B
both had coins in the same pool as illustrated above. UTXO 1 would then be A+B+S || S in 1 month and this would branch off in a tree to two off-chain UTXOs with A+S || S in 1 month and B+S || S in 1 month. If both A
and B
forfeit their claim as expected, the off-chain UTXOs will never go on-chain. This works with any number of users and is what makes the protocol efficient.
Creating this transaction structure currently requires A+B+S to pre-sign, meaning all recipients have to interact with each other whenever a new UTXO is being created. OP_CTV would remove that requirement (update: this scheme similarly reduces interactivity without requiring CTV).
A single user might publish a REDEEM_TX. That single user will have to pay the fees to expand the tree of off-chain transactions and reach their specific output. This is costly to that user and thus puts a economic limit on what the smallest viable denomination inside Ark could be.
Also, since the tree got expanded, S
now has to spend log(n) outputs instead of 1 in order to claim the funds.
Instead of swapping for a new off-chain REDEEM_TX with S
, it is also simply possible to swap for an on-chain output without any timelocks, allowing for an optimally efficient exit.
The transaction that contains UTXO_2 could contain another small ANCHOR_OUTPUT that can only be spent by S
. A
can then include it as an input to her FORFEIT_TX to S
. Now the FORFEIT_TX can't be sent on-chain unless the transaction containing UTXO_2 as well as the ANCHOR_OUTPUT go on-chain first, thus fulfilling the "if UTXO_2 exists" condition.
The ANCHOR_OUTPUT can be kept off-chain by placing it inside an off-chain tree of transactions, though this does mean S has to expand the tree if it ever needed the anchor.
The main upside is the simplified interaction and no messy issues with eviction - spending coins doesn't require you to interact with all the people in the pool, just S
.
The main downside is reduced liquidity - the coins the Server receives back won't be available to them immediately, so the faster coins move hands, the more of S
's liquidity becomes locked up. If we assume a locktime of 30 days and on average 1BTC moving hands every 10 minutes, then S
will end up having 6 * 24 hours * 30 days = 4320BTC locked up.
A transfer isn't complete until the relevant UTXO confirms on-chain. However, if the recipient is willing to trust S
never to change transactions that are waiting to be confirmed, transfers could be subjectively viewed as instant.
The aim of this write-up was to concisely explain the core concepts behind Ark, as the original documentation has been difficult for many (myself included) to comprehend. Full accuracy was not the goal - and a lot of it was educated guess work / reverse engineering - so the actual Ark design will perhaps differ somewhat (though hopefully not massively) from what is written here.
The one I did design [1] fortunately has no required interactivity, but I can see how coinjoins for other chains need to deal with many possible attacks that aggravate with longer running times.
[1] https://bitcointalk.org/index.php?topic=567625.msg56288711#msg56288711
[1]