Skip to main content

Atomic transfer

The purpose of the atomic transfer protocol is to enable two (or more) coin transfers to be completed in a way that they all complete or none of them do. This effectively means that the transfer-receiver function and key update is only completed if both receivers have the correct information to proceed. Once each receiver has verified that the transfer message they have received is valid, then the other parties can be allowed to complete transfer-receiver.

To enable this there needs to be a mechanism to prevent the transfer-receiver being completed before the other parties have verified and confirmed their transfer messages. If all parties verify, then transfer-receiver can proceed, otherwise the key shares are not updated and ownership of the coins remains with the inital owner.

The process is performed by each party in the atomic transfer supplying a batch_id in the transfer-sender message. The use of this (as opposed to leaving this null) is that the statecoin is put into a special locked state for a configured timeout period after the first batch_id is submitted. During this locked status two things are prevented 1) The sender cannot perform another /transfer/sender operation on the same coin (i.e. to send to a different address) and 2) /transfer/receiver cannot be performed until all coins with the same batch_id are unlocked by all the owners unlocking the coins with a new /transfer/unlock function. At the end of the timeout (if all coins with a specified batch_id have not been unlocked), the /transfer/receiver function will still be blocked (i.e. return error) but the original owner can repeat /transfer/sender again with a null batch_id to regain control of the coin.

Protocol

The statechain_transfer DB table can have 3 additional columns: batch_id (string), batch-time (integer) and locked (boolen). By default batch_id, batch-time are null and locked is false. The server is configured with batch-timeout parameter in seconds (in practice this will be some number of minutes). This is set in the server Settings.

The atomic transfer will then proceed as follows:

  1. The two or more parties that want to engage in an atomic transfer cooperate and share a batch_id (this is just a random UUID generated by one of the participants and shared with the other). One party can generate it and share with the others.
  2. The parties each generate a ml1 address that they want the coin they will recieve paid to and send to the sender.
  3. Each party performs /transfer/sender {statechain_id, batch_id, auth_sig, new_user_auth_key} with the batch_id paying to the receiving party new_user_auth_key and then create and upload the transfer message.
  4. If the batch_id is set in a /transfer/sender call (and not null) the server adds this to the batch_id DB column for the specified statechain_id and updates the locked status to true.
  5. The server then checks all other statecoins to see if the same batch_id is used for any other coin in the table.
  6. If there are no other coins with this batch_id, then it adds the current time (unix epoch time in seconds) to the batch-time column.
  7. If there are any other coin(s) with this same batch_id then the batch-time of those coin(s) is copied to the specified coin batch-time column.

This means that all coins where /transfer/sender have the same batch_id will have the same batch-time set.

With this logic, it does not mater which order the coins call /transfer/sender, the first call with a specific batch_id will set the initial batch-time for the atomic transfer.

When /transfer/sender is called for any coin, if batch-time + batch-timeout (as read from the DB table) is greater than or equal to the current time (i.e. the coin is still within the timeout period) then it will return an error (ERROR: statecoin batch locked).

When /transfer/sender is called for any coin, if batch-time + batch-timeout (as read from the DB table) is less the current time (i.e. the timeout period has ended) the server will check the DB table for any other coins have the same batch_id. For each coin that shares the samebatch_id, if all locked values are false, then the transfer-sender returns with an error (ERROR: batch transfer completed) (in this case all participants have verified the transfer message and the atomic transfer must complete - all parties must perform transfer-receiver). If all locked values are NOT false /transfer/sender can be called again with a null or different batch_id. If called with null batch_id then batch-time is set to null and locked to false.

  1. Each participant in the atomic transfer then polls /transfer/get_msg_addr with their receive address within the timeout period. If they receive a transfer message, they fully verify as usual. If the verification passes, then the participant calls a function /transfer/unlock {statechain_id, auth_sig} which changes the locked status of the coin (statechain_id) in the DB table to false. If the batch-time + batch-timeout is less than the current time, then the /transfer/unlock function should not unlock and instead return an error.

  2. Each participant then calls transfer-reciever. If /transfer/receiver is called on any coin and batch_id and batch-time are set (not null) and locked is false, then the server checks if any other coins in the DB table have the same batch_id. For alls coin that share the same batch_id, if all locked are false, then the function proceeds with the key update, otherwise it returns with an error (ERROR: coin in locked state). If /transfer/receiver is called on any coin and batch_id and batch-time are set (not null) and locked is true, then this function should return an error.

The outcomes of this protocol:

Any coins where /transfer/sender is called with a specific batch-id within the batch-time of the first one to call, will be added to the batch transfer.

Then, if all parties coins progress to call /transfer/unlock within the batch-time then /transfer/receiver can be performed for all coins by each party.

If any single participant doesn't call /transfer/unlock within the batch-time then no-one can call /transfer/receiver but after the batch-time expiry each owner can call /transfer/sender again to recover the coin (i.e. send to to their own address with null batch_id and then calling transfer-receiver).