BIP: XX Title: Atomic Cross Chain Transfers Author: Noel Tiernan <tier.nolan@gmail.com> Status: Draft Type: Standards Track Created: 2014-04-29
Table of Contents |
Abstract
This BIP describes a method for atomically trading coins between Bitcoin and a Bitcoin-like alternative coin (altcoin).
Motivation
There are many coin trading exchanges. These websites allow users to trade Bitcoins for altcoin, and also to trade one type altcoin for another.
These sites are centralised in nature. A p2p coin trading system requires a way for traders to trade their coins in an atomic way.
Protocol Overview
The protocol defined in this BIP consists of two stages. In the first stage, the parties cooperate to generate a set of transactions, without broadcasting. In the second stage, the transactions are broadcast in a specific ordering. Communication between the parties is only required during the first stage.
Each party has an incentive to participate in the defined broadcast ordering. If the protocol stops at any stage before the transaction is committed, both parties can recover their funds using timelocked refund transactions.
It is assumed that Bob wishes to buy A altcoins (ATC) from Alice for B Bitcoins (BTC). Transaction fees are assumed to be fb for the Bitcoin network and fa for the altcoin network. Bob will pay all Bitcoin fees and Alice will pay all altcoin fees. The exchange price agreed between the parties will take this into account.
Public keys are referred to as pub-AN for Alice's keys and pub-BN for Bob's keys. An optional 3rd party signature is also possible, designated pub-T.
The third party is only required to protect against transaction malleability. Once transaction malleability is resolved, the third party will not be necessary.
An additional standard transaction type is required on one of the networks for the protocol to operate. Trades can be performed between a network which supports P2SH and other that supports OP_HASH160 transaction locking.
Transaction Creation
1) Alice sends Bob three public keys (pub-A1, ..., pub-A3)
2) Bob sends Alice three public keys (pub-B1, ..., pub-B3) and Hash160(x)
x = serialized{pub-B4 OP_CHECKSIG}
3) Both parties creates their "bail-in" transaction.
Transaction output 0 can only be spent with both parties' signatures. Transaction output 1 can only be spent by Bob, but it results in x being revealed.
Name: Bob.Bail.In Input value: B + 2*fb + change Input source: (From Bob's coins, multiple inputs are allowed) Output 0 value: B ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL Output 1 value: fb ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUALVERIFY pub-A1 OP_CHECKSIG Output 2 value: change ScriptPubKey 2: <= 100 bytes
P2SH Redeem: OP_2 pub-A1 pub-B1 OP_2 OP_CHECKMULTISIG P2SH Redeem: OP_2 pub-A1 pub-B1 pub-T OP_3 OP_CHECKMULTISIG
Transaction output 0 can only be spent with both parties' signatures. Transaction 1 can only be spent by Alice, but it requires x to be reveals by Bob first.
Name: Alice.Bail.In Input value: A + 2*fa + change Input source: (From Alice's altcoins, multiple inputs are allowed) Output 0 value: A ScriptPubKey 0: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL Output 1 value: fa ScriptPubKey 1: OP_HASH160 Hash160(x) OP_EQUAL Output 2 value: change ScriptPubKey 2: <= 100 bytes
P2SH Redeem: OP_2 pub-A1 pub-B1 OP_2 OP_CHECKMULTISIG P2SH Redeem: OP_2 pub-A1 pub-B1 pub-T OP_3 OP_CHECKMULTISIG
Note: x = serialized{pub-B4 OP_CHECKSIG}
The shorter version of P2SH Redeem should be used when a third party is not used.
Output 1 uses P2SH, this means that Bob must provide x in order to spend it.
If a third party isn't used, then pub-T is not included and the key count (OP_3) is replaced by OP_2.
4) Bob and Alice exchange bail-in transaction hashes
Bob sends Alice Hash256(Bob.Bail.In)
Alice sends Bob Hash256(Alice.Bail.In)
Note: The outputs in the bail-in transaction do not need to be ordered as given in steps 1 and 2.
5) Both parties create the payout transactions
This transaction can be spent by Alice. Since it has Bob.Bail.In:1 as an input, it cannot be signed unless Bob reveals x.
Name: Alice.Payout Input value: B Input source: Bob.Bail.In:0 Input value: fb Input source: Bob.Bail.In:1 Output value: B ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL
P2SH Redeem: pub-A2 OP_CHECKSIG
This transaction can be spent by Bob. However, since it has Alice.Bail.In:1 as an input, he cannot sign the inputs unless he reveals x.
Name: Bob.Payout Input value: A Input source: Alice.Bail.In:0 Input value: fa Input source: Alice.Bail.In:1 Output value: A ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL
P2SH Redeem: pub-B2 OP_CHECKSIG
6) Both parties create the refund transactions
This transaction is timelocked, so that it can't be spent until the timeout (T) has passed. This transaction does not require Bob.Bail.In:B, so Bob does not have to reveal x in order to spend it.
Name: Bob.Refund Input value: B Input source: Bob.Bail.In:0 Output value: B - fb ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL Locktime: (current block height) + (T / 10 minutes)
P2SH Redeem: pub-B3 OP_CHECKSIG
This transaction is timelocked, so that it can't be spent until half the timeout (T/2) has passed. This transaction does not require Alice.Bail.In:B, so Alice can spend it without x being revealed.
Name: Alice.Refund Input value: A Input source: Alice.Bail.In:0 Output value: A - fa ScriptPubKey: OP_HASH160 Hash160(P2SH Redeem) OP_EQUAL Locktime: current block height + ((T/2)/(altcoin block rate))
P2SH Redeem: pub-A3 OP_CHECKSIG
7) Bob and Alice exchange signatures
Bob sends Alice signatures for Alice.Payout (Input: Bob.Bail.In:0) and Alice.Refund.
Alice signs all three and now has 3 signed transactions. Alice.Payout cannot be fully signed until x is revealed.
Alice sends Bob signatures for Bob.Payout (Input: Alice.Bail.In:0), Bob.Refund and Bob.Trusted.Refund.
Bob signs all three and has 3 fully signed transactions.
8) Exchange of bail-in transactions
The parties can safely exchange bail-in transactions at this point. This is not necessary for the protocol, but would allow both parties to verify that the other party at least has a valid bail-in transaction before locking their funds.
No further communication is required between the parties. Bob and Alice can determine the state of the transaction by monitoring both chains.
Transaction Broadcast
The transactions must be broadcast in a specific order for the composite transaction to be atomic.
Bob has the following transactions:
- Bob.Bail.In: Bob's bail-in transaction
- Bob.Refund: Bob's refund transaction (timelocked until the timeout has passed)
- Bob.Payout: Bob's altcoin payout transaction (can only be spent by revealing x)
- Alice.Payout: Alice's Bitcoin payout transaction (can only be spent if Bob reveals x)
- Alice.Bail.In: Alice's bail-in transaction
- Alice.Refund: Alice's refund transaction (timelocked until half the timeout has passed)
Step 1: Bail-in by Bob
Bob broadcasts Bob.Bail.In.
Bob's has no option other than waiting
- He cannot broadcast Bob.Refund since it is timelocked
- He cannot broadcast Bob.Payout since it has Alice.Bail.In as an input
- She cannot broadcast Alice.Payout since she doesn't know x
- She cannot broadcast Alice.Refund since it is timelocked
- She can broadcast Alice.Bail.In, which moves the protocol to step 2
Step 2: Bail in by Alice
Alice broadcasts Alice.Bail.In.
Alice has no option other than waiting
- She cannot broadcast Alice.Refund since it is timelocked
- She cannot broadcast Alice.Payout since she doesn't know x
- He cannot broadcast Bob.Refund since it is timelocked
- He can broadcast Bob.Payout since Alice.Bail.In has been broadcast
Step 3: Bob commits to the transaction
Bob broadcasts Bob.Payout to claim his altcoins. To spend the 2nd output of Alice.Bail.In requires that Bob reveal x.
This completes Bob's participation in the protocol.
Once Alice.Bail.In has been confirmed to a sufficient depth, Bob should broadcast Bob.Payout as soon as possible. Since broadcasting Bob.Payout reveals x, if Bob waits until the the locktime on Alice.Refund has expired (or is near to expire), then it creates a race condition. Alice could broadcast Alice.Refund to get her altcoins back and also broadcast Alice.Payout to claim Bob's Bitcoins.
If he broadcasts immediately, he has half the timeout time for his transction to be confirmed.
Alice has only one broadcast option
- She cannot broadcast Alice.Refund since it is timelocked
- She can broadcast Alice.Payout since she knows x, which moved the protocol to step 4
Step 4: Alice completes the transaction
Alice broadcasts Alice.Payout to claim her Bitcoins.
If Alice doesn't claim her Bitcoins before the timeout on Bob.Refund ends, then Bob could use Bob.Refund to recover the Bitcoins he used in the trade.
Since Bob can wait at most half the timeout (T/2) before completing step 3 and Bob.Refund has a timelock of T, Alice has at least half the timeout (T/2) to broadcast Alice.Payout.
Specification
JSON-RPC shall be used for communication between the parties.
Hex encoding shall be used for all byte arrays.
Public keys must be serialized using strict SEC format:
byte(0x02) byte_array(32): Compressed even key byte(0x03) byte_array(32): Compressed odd key
Compressed keys are mandatory.
When included in transactions, hash_type must be set to 1.
Signatures must be serialized using strict DER format.
byte(0x30) byte(total_length) byte(0x02) byte(len(R)) byte_array(len(R)) byte(len(s)) byte_array(len(s))
total_length is equal to 3 + len(R) + len(S).
R and S are represented in signed Big Endian format without leading zeros, except that exactly one leading zero is mandatory, if the number would otherwise be negative. This occurs if the MSB in the first non-zero byte is set.
Transactions shall be serialized using the bitcoin protocol serialization. Transactions that are not timelocked should have a lock_time and sequence number of 0. Timelocked inputs should have a sequence number of UINT_MAX (0xFFFFFFFF).
One party shall act as server and one party shall act as client.
The party which selects x and has the longer timeout is defined as the slow trader. The other party is the fast trader.
Request Message
Each message shall have the following format.
{"id":1, "method": "method.name", "params": [param1, param2]}
id: The method id, it should increment for each method call method: The name of the method params: The method parameters
Result Message
The server shall reply to Request methods with a response message.
{"id": 1, "result": result, "error: Null}
Error Message
The server shall reply with an error message, if the request is invalid.
{"id": 1, "result": Null, "error: [error_code, "error_string"]}
Methods
The following methods must be supported.
Trade Request
This method is used to initiate the protocol.
{"id":1, "method": "trade.request", [version, long_deposit, [third_parties], k_client, sell_magic_value, sell_coin_amount, sell_coin_fee, sell_locktime, buy_magic_value, buy_coin_amount, buy_coin_fee, buy_locktime]}
The parameters are defined as
version: Integer version of the handshake (should be set to 1) slow_trader (boolean): True if the server is the slow trader, false otherwise third_party (list of string): Hex encoding of acceptable 3rd parties' public key (or Null for no 3rd party) k_client (string): A random hex encoded byte array (32 bytes) sell_coin_magic_value (string): Hex encoding of the network magic value for the coin being sold sell_coin_amount (number): An integer count of the number of coins being sold (in the smallest units) sell_locktime (number): The int locktime for the client's refund transaction buy_coin_magic_value (string): Hex encoding of the network magic value for the coin being bought buy_coin_amount (number): An integer count of the number of coins being bought (in the smallest units) buy_locktime (number): The int locktime for the server's refund transaction
The server can decide if the trade is acceptable.
For altcoins with irregular block rates, ensuring that the timeouts occur in the correct order may be difficult. It is recommended that the more stable chain act as slow trader. This prevents the slow trader having to wait an extended period if the altcoin's block rate collapses.
Note: The locktime can mean timestamp and block height depending on value.
The response for the method has a subset of the trade information.
{"id":1, "result": [version, slow_trader, [third_parties], k_server, sell_coin_amount, sell_coin_fee, sell_locktime, buy_coin_amount, buy_coin_fee, buy_locktime] "error": Null}
If the returned values match the request, then the trade is accepted. Otherwise, it is a counteroffer.
If the server doesn't support the protocol version requested by the client, the version in the response should be equal to the highest supported version, and no other parameters included. Otherwise, the server should respond with the requested version.
An accepted offer should have at most one 3rd party's public key in the public key list.
If the server does not wish to trade in that coin at all, then the buy_coin_amount, _fee and _locktime should be set to Null in the response.
If the exchange rate is insufficient, servers should modify the sell_coin_amount in preference to modifying the buy_coin_amount.
Servers should accept trades if the client echos back the response to the server.
A trade-id is generated for each transaction (| means concatenation).
tr_id = SHA-256(k_client | k_server)
The result of the SHA-256 operation is considered a big endian encoded unsigned integer.
If tr_id falls outside the elliptic curve finite field, the server should select a different byte array and repeat until success.
The third party's public key is modified to give
third_party_key_modified = tr-id * third_party_key
This key should be used to generate the third party's refund transaction.
Exchange Keys
This method is used to exchange public keys between the parties. Each party has to provide 5 public keys and the long trader must provide hash_x. The slow trader should set hash_x to Null.
{"id": 1, "method":"keys.request", "params": [tr_id, key1, key2, ... key5, hash_x]}
The server responds with 5 public keys and hash_x.
{"id": 1, "result": [key1, key2, ... key5, hash_x], "error": Null}
Exchange Bail-in Transaction Hashes
This method is for exchanging bail-in transaction hashes and the A and B indexes.
{"id": 1, "method":"k, bail_in_hash.request", "params": [tr_id, client_bail_in_hash]}
The server responds with its own bail-in transaction hash.
{"id": 1, "result":"server_bail_in_hash", "error": Null}
Both hashes should be encoded as 64 character (32 byte) hashes.
Note 1: This is the transaction id hash, not hash160. Note 2: The fast and slow trader's bail-in transactions are constructed differently.
Exchange Signatures
This method is for the parties to exchange signatures.
{"id": 1, "method": "exchange.signatures", "params": [tr_id, server_payout_signature, server_refund_signature, server_third_party_signature]
The parameters are defined as
server_payout_signature: This is the signature for the server's payout transaction (input A) server_refund_signature: This is the signature for the server's timelocked refund transactions server_third_party_signature: This is the signature for the server's transaction to direct the output to a third party
The response is of the same form
{"id": 1, "result": [client_payout_signature, client_refund_signature, client_third_party_signature], "error": Null}
The parameters are defined as
client_payout_signature: This is the signature for the client's payout transaction (input A) client_refund_signature: This is the signature for the client's timelocked refund transactions client_third_party_signature: This is the signature for the client's transaction to direct the output to a third party
Once the 3 signatures are exchanged, no further communication is required.
Exchange Bail-in Transactions
This method is for the parties to exchange bail-in transactions. This allows both parties to broadcast both bail-in transactions.
Broadcasting the bail-in transaction prior to this step reduces malleability risk by the other party.
{"id": 1, "method": "exchange.bail.in", params: [tr_id, server_bail_in]}
The response is of the same form
{"id": 1, "result": [client_bail_in], "error": Null}
Trade Cancel
This allows the parties to back out of a trade before the timeouts are completed. It is a courtesy and not enforceable.
{"id": 1, "method": "cancel.transaction", "params": "unlocked_server_refund_signature"}
The parameters are defined as
unlocked_server_refund_signature: This is the signature for the server's refund transaction with locktime set to zero.
The response is
{"id": 1, "result": [unlocked_client_refund_signature]}
The parameters are defined as
unlocked_client_refund_signature: This is the signature for the client's refund transaction with locktime set to zero.
Since this method is only a courtesy, it doesn't matter that the server could fail to provide the client with the refund transaction.
Once this method is used, the parties should not proceed to step 3.
Third Party Arbitration
This method is for submitting transactions to third parties.
{"id": 1, method:"arbitrate", "params": [tr_id third_party_key bail_in_p2sh_redeem refund_transaction new_transaction]}
The parameters are defined as
tr_id: The tr_id parameter encoded as a integer third_party_key: The third party's unmodified public key bail_in_p2sh_redeem: The P2SH Redeem script for the bail-in transction refund_transaction: The refund transactions, fully signed new_transaction: This is the new refund transaction
The third party must
* Verify that the refund transaction spends the p2sh_redeem script * Verify that the refund and new transaction are identical except for tx-in hashes
The new transaction may have additional outputs. This allows the third party to be paid.
The response is
{"id": 1, "result": [new_transaction_signature], "error": Null}
The third party doesn't have to monitor all the chains. As long as it doesn't allow the locktime to be modified or outputs to be redirected, the system remains secure.
Compatibility
The protocol outlined in this BIP requires the use of a single non-standard scriptPubKey.
The Bob.Bail.In transaction has a scriptPubKey of the following form.
OP_HASH160 Hash160(x) OP_EQUAL_VERIFY pub-A1 OP_CHECKSIG
All the other scriptPubKeys are standard transactions.
If the transaction is only standard on one of the two networks, then the party selling coin on that network should be the fast trader.
Reference Implementation
TBD
References
[1] https://bitcointalk.org/index.php?topic=193281.0
Copyright
This document is placed in the public domain.