Atomic Cross Chain Swap by Qitmeer

Introduction of HTLC

A Hash Time Locked Contract or HTLC is a class of payments that enables trading tokens across different blockchains securely without using an intermediary party in the process. Two parties can claim payments by disclosing their own preimage of a hash once tokens have been locked into their hash-lock contracts upon a mutual agreed timeout threshold.

The implementation process of HTLC is as following:

Alice owns Meer, she needs MEER -> BTC;
Bob owns BTC, he needs BTC -> MEER;
Alice initials the transaction
  1. Alice generates her Secret Key and Secret Key Hash (generally, we use RIPEMD 160 for UTXO and SHA256 for ETH main chain);

  2. Alice generates the hash-lock contract – Meer with her Secret key;

  3. Alice transfer 10 Meer to the hash-lock contract;

  4. Bob verifies the hash-lock contract and address and uses the Secret Key Hash to generate the corresponding contract on BTC;

  5. Alice uses Secret Key to claim “BTC” from Bob’s BTC contract;

  6. Bob uses Secret Key to claim “Meer” from Alice’s Meer Contract;

  7. Transaction completes without knowing each other;

  8. The creator of the hash-lock contract can get the tokens back if transactions didn’t complete after the timeout reached to avoid any loss.

Case 1: Atomic Swap between Meer and BTC

qx command and
bx command will be used to generate contracts

Step 1: Generate addresses respectively

Alice MEER PublicKeyHash = 8dc268a8e2876b941b95f3bd3b71050f003c5383;
Alice BTC PublicKeyHash = 843043481f636dafd10cb0433d4f34456eb3c840
Alice BTC Address = msZuJjb9m8pDMRNDRvaYCz9JcLTQt58RCZ;
Alice MEER Address = TmbsdsjwzuGboFQ9GcKg6EUmrr3tokzozyF;

Bob MEER PublicKeyHash  = cdd006e3adcd991a15f46c7e975686c1aec20773;
Bob BTC PublicKeyHash  = 46d96e0eb3f7de705b860347e451b9c41af72cd2;
Bob BTC Address = mmya4n31E5TZodgWxrtn3nXQhU2HLZA19E;
Bob MEER Address = TmhiKSDgr8SrGxEe7v6ee1TWY4FA6Nq5AQL;

Step 2: Generate Secret Key and Secret Key Hash

Alice generates her Secret Key and Secret Key Hash;

qx entropy

Secret Key

7bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa

Generate Secret Key Hash

qx ripemd160 7bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa

Secret Key Hash

b75e2a5d3954e063a1de032caa7baed1029fa1e9

Step 3: Generate HTLC

A HTLC must include hash lock and time lock, a standard OP contract as follows:

OP_IF
    OP_RIPEMD160 
    # Secret Key Hash
    b75e2a5d3954e063a1de032caa7baed1029fa1e9 OP_EQUALVERIFY
    OP_DUP OP_HASH160 
    # Bob MEER PublicKeyHash
    cdd006e3adcd991a15f46c7e975686c1aec20773 
OP_ELSE
    # 2019.08.03 00:00:00
    005e445d 
    OP_CHECKLOCKTIMEVERIFY
    OP_DROP OP_DUP OP_HASH160 
    # Alice PublicKeyHash
    8dc268a8e2876b941b95f3bd3b71050f003c5383 
OP_ENDIF OP_EQUALVERIFY OP_CHECKSIG

This contract indicates that if Bob could provide the secret key which can be hashed to b75e2a5d3954e063a1de032caa7baed1029fa1e9 by RIPEMD160, then he can claim the payment. If the fund was unspent after 2019.08.03 00:00:00, Alice will claim this payment.

Contract script can be generated by bx tool;

bx script-encode "if ripemd160 [b75e2a5d3954e063a1de032caa7baed1029fa1e9] equalverify dup hash160 [cdd006e3adcd991a15f46c7e975686c1aec20773] else [005e445d] checklocktimeverify drop dup hash160 [8dc268a8e2876b941b95f3bd3b71050f003c5383] endif equalverify checksig"

HTLC Script

63a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac

Generate Contract Address

qx hash160 63a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac | qx base58check-encode -v 0ee2

MEER HTLC Contract Address

TSPLoxLYMoAvkn2mqp27BW2aLmnk9n15L96

Step 4: Initiate transaction and announce in the network

Transfer 10 Meer to the address TSPLoxLYMoAvkn2mqp27BW2aLmnk9n15L96 from wallet or use qx command and kahf to initiate the transaction and announce in the network.

To acquire UTXO

 ./kahf out -u TmbsdsjwzuGboFQ9GcKg6EUmrr3tokzozyF
1001d56dfbecb146aa8eb1c387d497ee5983bdb4dcea09649a267659ade2b284:2

Use qx command to initiate transaction:

qx tx-encode -i 1001d56dfbecb146aa8eb1c387d497ee5983bdb4dcea09649a267659ade2b284:2 -l 0 -o TmbsdsjwzuGboFQ9GcKg6EUmrr3tokzozyF:12.499 -o TSPLoxLYMoAvkn2mqp27BW2aLmnk9n15L96:10 | qx tx-sign -k <Alice private>
010000000184b2e2ad5976269a6409eadcb4bd8359ee97d487c3b18eaa46b1ecfb6dd5011002000000ffffffff02e0f57f4a000000001976a9148dc268a8e2876b941b95f3bd3b71050f003c538388ac00ca9a3b0000000017a914cc31cdfb555db880111cc7df793830bb7ecf6ce087000000000000000001000000000000000000000000000000006a47304402206d0b6c4671c2ce0db2efd619a0dc6e1fe56ea133ea7842dc7690f4d9a32dc05a0220335642c36009fe509d1462f06a69450e5c8df09a23b45d47df50a134a2847c1f01210354455a60d86273d322eebb913d87f428988ce97922a366f0a0867a426df78bc9

Announce transaction:

Use [qitmeer-cli] to send transaction

./qitmeer-cli sendRawTransaction 010000000184b2e2ad5976269a6409eadcb4bd8359ee97d487c3b18eaa46b1ecfb6dd5011002000000ffffffff02e0f57f4a000000001976a9148dc268a8e2876b941b95f3bd3b71050f003c538388ac00ca9a3b0000000017a914cc31cdfb555db880111cc7df793830bb7ecf6ce087000000000000000001000000000000000000000000000000006a47304402206d0b6c4671c2ce0db2efd619a0dc6e1fe56ea133ea7842dc7690f4d9a32dc05a0220335642c36009fe509d1462f06a69450e5c8df09a23b45d47df50a134a2847c1f01210354455a60d86273d322eebb913d87f428988ce97922a366f0a0867a426df78bc9
db0e8712b6bf1a0c7f746581abaa1566c8d090e5275837053c00909c8332ed23

Step 5: Bob generates a BTC contract

Bob generates a corresponding contract with the Secret Key Hash from TSPLoxLYMoAvkn2mqp27BW2aLmnk9n15L96 script to acquire the Secret Key.

bx script-decode 63a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac
if ripemd160 [b75e2a5d3954e063a1de032caa7baed1029fa1e9] equalverify dup hash160 [cdd006e3adcd991a15f46c7e975686c1aec20773] else [005e445d] checklocktimeverify drop dup hash160 [8dc268a8e2876b941b95f3bd3b71050f003c5383] endif equalverify checksig

# Secret Key Hash b75e2a5d3954e063a1de032caa7baed1029fa1e9

BTC Contract:

OP_IF
    OP_RIPEMD160 
    # Secret Key Hash
    b75e2a5d3954e063a1de032caa7baed1029fa1e9 OP_EQUALVERIFY
    OP_DUP OP_HASH160 
    # Alice BTC PublicKeyHash
    843043481f636dafd10cb0433d4f34456eb3c840 
OP_ELSE
    # 2019.08.02 00:00:00
    800c435d  
    OP_CHECKLOCKTIMEVERIFY
    OP_DROP OP_DUP OP_HASH160 
    # Bob BTC PublicKeyHash
    46d96e0eb3f7de705b860347e451b9c41af72cd2 
OP_ENDIF OP_EQUALVERIFY OP_CHECKSIG

Generate BTC HTLC address

bx script-encode "if ripemd160 [b75e2a5d3954e063a1de032caa7baed1029fa1e9] equalverify dup hash160 [843043481f636dafd10cb0433d4f34456eb3c840] else [800c435d] checklocktimeverify drop dup hash160 [46d96e0eb3f7de705b860347e451b9c41af72cd2] endif equalverify checksig" | bx bitcoin160 | bx base58check-encode -v 196

Contract Script:

63a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914843043481f636dafd10cb0433d4f34456eb3c8406704800c435db17576a91446d96e0eb3f7de705b860347e451b9c41af72cd26888ac

Contract address

2MzaXi88QtpDLjxks4GEqfyZcfWybHbfAgc

Transfer 0.001 BTC to the wallet address

txid: 6c14149ee55a334262565333a2e4ef5779597dbc36f97c1e51657e01e70fe2f9

Transaction track explorer

Step 6: Alice claims BTC (Atomic Swap)

Alice claims the BTC from 2MzaXi88QtpDLjxks4GEqfyZcfWybHbfAgc with Secret Key

bx tx-encode -i 6c14149ee55a334262565333a2e4ef5779597dbc36f97c1e51657e01e70fe2f9:0 -o msZuJjb9m8pDMRNDRvaYCz9JcLTQt58RCZ:90000
0100000001f9e20fe7017e65511e7cf936bc7d597957efe4a23353566242335ae59e14146c0000000000ffffffff01905f0100000000001976a914843043481f636dafd10cb0433d4f34456eb3c84088ac00000000

Sign for the transaction:

bx input-sign <Alice private> "if ripemd160 [b75e2a5d3954e063a1de032caa7baed1029fa1e9] equalverify dup hash160 [843043481f636dafd10cb0433d4f34456eb3c840] else [800c435d] checklocktimeverify drop dup hash160 [46d96e0eb3f7de705b860347e451b9c41af72cd2] endif equalverify checksig" 0100000001f9e20fe7017e65511e7cf936bc7d597957efe4a23353566242335ae59e14146c0000000000ffffffff01905f0100000000001976a914843043481f636dafd10cb0433d4f34456eb3c84088ac00000000
304402206fb35f56b061f40b4ae92bef3e7e86c722e3cebf566b3fd3cb3c0c5ceee28d2902202032ee015f1a20ba21a38e6471336907a8210b15f87ed51f9e661dde55bc2b1f01

Configure unlock script:

Unlock script as below

# < signature > < Alice publicKey > < Secret Key > OP_1 < contract script >
bx input-set "[304402206fb35f56b061f40b4ae92bef3e7e86c722e3cebf566b3fd3cb3c0c5ceee28d2902202032ee015f1a20ba21a38e6471336907a8210b15f87ed51f9e661dde55bc2b1f01] [0354455a60d86273d322eebb913d87f428988ce97922a366f0a0867a426df78bc9] [7bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa] 1 [63a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914843043481f636dafd10cb0433d4f34456eb3c8406704800c435db17576a91446d96e0eb3f7de705b860347e451b9c41af72cd26888ac]"  0100000001f9e20fe7017e65511e7cf936bc7d597957efe4a23353566242335ae59e14146c0000000000ffffffff01905f0100000000001976a914843043481f636dafd10cb0433d4f34456eb3c84088ac00000000
0100000001f9e20fe7017e65511e7cf936bc7d597957efe4a23353566242335ae59e14146c00000000df47304402206fb35f56b061f40b4ae92bef3e7e86c722e3cebf566b3fd3cb3c0c5ceee28d2902202032ee015f1a20ba21a38e6471336907a8210b15f87ed51f9e661dde55bc2b1f01210354455a60d86273d322eebb913d87f428988ce97922a366f0a0867a426df78bc9207bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa514c5163a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914843043481f636dafd10cb0433d4f34456eb3c8406704800c435db17576a91446d96e0eb3f7de705b860347e451b9c41af72cd26888acffffffff01905f0100000000001976a914843043481f636dafd10cb0433d4f34456eb3c84088ac00000000
txid: db675bd88d8e67923954d2569aaf2468a56b594586239062eaa39bb5deca2b0a

Transaction Track Explorer

Step 7: Bob claims Meer (Atomic Swap)

Bob gets Secret Key (7bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa) from scriptSig of the BTC transaction db675bd88d8e67923954d2569aaf2468a56b594586239062eaa39bb5deca2b0a and claim 10 Meer from TSPLoxLYMoAvkn2mqp27BW2aLmnk9n15L96

To claim Meer:

Use qitmeer.js API & library to complete the transaction

const qitmeerJs = require('qitmeer.js')

function MeerUnit( num ) {
    return parseInt(num * 100000000)
}

function privateKeyToMeerP2PKH ( privateKeyBuffer ) {
    const keyPair = qitmeerJs.ec.fromPrivateKey(privateKeyBuffer)
    const hash160 = qitmeerJs.hash.hash160(keyPair.publicKey)
    const p2pkhAddress = qitmeerJs.address.toBase58Check(hash160, qitmeerJs.network.testnet.pubKeyHashAddrId)
    return {
        p2pkhAddress,
        keyPair
    }
}

function creatMEERP2SHTransaction({ privateKeyBuffer , amount, utxo, toAddress, contractScript,sigScript, lockTime, needsig } ) {
    const {p2pkhAddress, keyPair} = privateKeyToMeerP2PKH ( privateKeyBuffer )
    const publickey = keyPair.publicKey.toString('hex')
    const txb = qitmeerJs.txsign.newSigner(hlcnetwork);
    if (lockTime > 0) {
        txb.setLockTime(lockTime)
    }
    let amountAll = 0
    utxo.map( v => {
        const u = v.split(':')
        const inScript = {
            prevOutScript: qitmeerJs.script.fromBuffer(Buffer(contractScript+'','hex'))
        }
        if( lockTime > 0 ) inScript.sequence = 0
        amountAll += (u[2] || 0)*1
        txb.addInput( u[0], u[1]*1 ,inScript);
    })

    txb.addOutput( toAddress, MeerUnit( amount ));
    txb.addOutput( p2pkhAddress, MeerUnit( amountAll - amount - 0.0001 ));
    utxo.map( (v,i) => {
        txb.sign(i, keyPair);
        const transactionSign = txb.__inputs[i].signature.toString('hex');
        const s = (needsig?transactionSign.toString('hex') +' '+publickey+' ':'')+`${sigScript} ${contractScript}`
        txb.__tx.vin[i].script = qitmeerJs.script.fromAsm(s).toBuffer()
    })
    const newTransaction = txb.__tx.clone();
    return {
        Transaction: newTransaction.toBuffer().toString('hex'),
        RefundId: txb.getId()
    }
}

creatMEERP2SHTransaction ({
    privateKeyBuffer: Buffer('< Bob MEER privateKey >', 'hex') ,
    amount: 9.999,
    utxo: ['db0e8712b6bf1a0c7f746581abaa1566c8d090e5275837053c00909c8332ed23:1:10'],
    toAddress: 'TmhiKSDgr8SrGxEe7v6ee1TWY4FA6Nq5AQL',
    contractScript:'63a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac',
    sigScript: '7bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa OP_1',
    lockTime: 0,
    needsig: true
})
010000000123ed32839c90003c05375827e590d0c86615aaab8165747f0c1abfb612870edb01000000ffffffff026043993b000000001976a914cdd006e3adcd991a15f46c7e975686c1aec2077388ac8f5f0100000000001976a914cdd006e3adcd991a15f46c7e975686c1aec2077388ac00000000000000000100000000000000000000000000000000e0483045022100a61dda54c0f40b2b92b47034032602d7b7f8ea962f5772d0f83fa0bb3182831b0220311affc73e953ee2573ae2964ce06f9f85d18376258180fe375a5b6f5eb85351012103136ed2c501056a6f8e6d57578e24d36ff1055c552ff0f8a28ba7bb284efeec2a207bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa514c5163a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac

Announce the transaction

./qitmeer-cli sendRawTransaction 010000000123ed32839c90003c05375827e590d0c86615aaab8165747f0c1abfb612870edb01000000ffffffff026043993b000000001976a914cdd006e3adcd991a15f46c7e975686c1aec2077388ac8f5f0100000000001976a914cdd006e3adcd991a15f46c7e975686c1aec2077388ac00000000000000000100000000000000000000000000000000e0483045022100a61dda54c0f40b2b92b47034032602d7b7f8ea962f5772d0f83fa0bb3182831b0220311affc73e953ee2573ae2964ce06f9f85d18376258180fe375a5b6f5eb85351012103136ed2c501056a6f8e6d57578e24d36ff1055c552ff0f8a28ba7bb284efeec2a207bb05283f05a9b795bfbfd6a399b801ddf1fcd9e006a5ec24c9fa1cd826c8aaa514c5163a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac
txid: 6d5bdc381dfd9de4624f7d65a515cf2d5b5a6ce06458cbda4d867da7dae6837d

Step 8: Refund Meer to Alice if Bob didn’t complete transaction within the specific time

const qitmeerJs = require('qitmeer.js')

creatMEERP2SHTransaction ({
    privateKeyBuffer: Buffer('< Alice MEER privateKey >', 'hex') ,
    amount: 9.999,
    utxo: ['db0e8712b6bf1a0c7f746581abaa1566c8d090e5275837053c00909c8332ed23:1:10'],
    toAddress: 'TmbsdsjwzuGboFQ9GcKg6EUmrr3tokzozyF',
    contractScript:'63a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac',
    sigScript: 'OP_0',
    lockTime: 156467520,
    needsig: true
})
txid: "890f4563c329ef376e1ae78150ee280e7074375d1eeca93023761046e5221a9a"

raw:
"010000000123ed32839c90003c05375827e590d0c86615aaab8165747f0c1abfb612870edb0100000000000000026043993b000000001976a9148dc268a8e2876b941b95f3bd3b71050f003c538388ac8f5f0100000000001976a9148dc268a8e2876b941b95f3bd3b71050f003c538388ac40815309000000000100000000000000000000000000000000be473044022009233c04dd89097001b39959b52394165c34fd887c03b4bd1f06c356e676e6f802200b8ede3b95404c88361c2c3397673376fa5d9c38bba565e74c77c66f660df44b01210354455a60d86273d322eebb913d87f428988ce97922a366f0a0867a426df78bc9004c5163a614b75e2a5d3954e063a1de032caa7baed1029fa1e98876a914cdd006e3adcd991a15f46c7e975686c1aec207736704005e445db17576a9148dc268a8e2876b941b95f3bd3b71050f003c53836888ac"

BTC and Meer cross chain swap completes

We are developing an APP to package the above complex procedures to make it user friendly for everyone.

Case 2: Atomic swap between Meer and USDT

Case 3: Atomic swap between Meer and ETH

Case 4: Atomic swap between Meer and ERC20 Token