Atomic swap example

API keys

Cryptoid API key

For operations on networks supported by chainz.cryptoid.info API a free API key is needed. This key has to be setup as an environment variable under the CRYPTOID_API_KEY key.

$ export CRYPTOID_API_KEY=YOUR_API_KEY

Etherscan API key

For operations on Etherscan API (e.q. find_redeem_transaction) a free API key is needed. This key has to be setup as an environment variable under the ETHERSCAN_API_KEY key.

$ export ETHERSCAN_API_KEY=YOUR_API_KEY

Infura API key

All the interactions with Ethereum network are done via infura.

$ export INFURA_TOKEN=YOUR_API_KEY

Bitcoin based networks

Assumptions

  • Alice has over 0.03 monacoins and wants to buy 0.001 litecoins
  • Alice doesn’t have a litecoin wallet
  • Bob has over 0.001 litecoins and wants to buy around 0.03 monacoin
  • Bob has a monacoin wallet

(2018-10-04) Exchange rate: 0.001 litecoins is 0.030 monacoin

1. Wallets setup

[Alice] has to create a new litecoin wallet

from clove.network import Litecoin

ltc_network = Litecoin()

alice_ltc_wallet = ltc_network.get_new_wallet()

alice_ltc_wallet.address
'LXRAXRgPo84p58746zaBXUFFevCTYBPxgb'

Check address on block explorer

alice_ltc_wallet.get_private_key()
# returns private key; The one below is fake, because of obvious security reasons.
'L15kFZg4MdoX2kqXEeEZMjbbVEdZzt1zL2vU59ynrtEf6GB16B3c'

[Alice] has to prepare her monacoin wallet

from clove.network import Monacoin

mona_network = Monacoin()

# Alice provides her private key. The one below is fake, because of obvious security reasons.
alice_mona_wallet = mona_network.get_wallet(private_key='cSYq9JswNm79GUdyz6TiNKajRTiJEKgv4RxSWGthP3SmUHiX9WKe')

alice_mona_wallet.address
'MPLx6eJS41da9bPsLLkHo35uY6KsHu7dXP'

Check address on block explorer

[Bob] can use his existing monacoin wallet by passing his private key

from clove.network import Monacoin

mona_network = Monacoin()

# Bob provides his private key. The one below is fake, because of obvious security reasons.
bob_mona_wallet = mona_network.get_wallet(private_key='cRoFBWMvcLXrLsYFt794NRBEPUgMLf5AmnJ7VQwiEenc34z7zSpK')

bob_mona_wallet.address
'MWsDkqHLonS5KfbRnRu3feByD9qkuj44Ye'

Check address on block explorer

[Bob] has to prepare his litecoin wallet

from clove.network import Litecoin

ltc_network = Litecoin()

# Bob provides his private key. The one below is fake, because of obvious security reasons.
bob_ltc_wallet = ltc_network.get_wallet(private_key='cTVuBqcjryCdHiCfFxkY5ycNPH2RYNrbmgrTVXBsLKG8xR2My3j2')

bob_ltc_wallet.address
'LUAn5PWmsPavgz32mGkqsUuAKncftS37Jq'

Check address on block explorer

2. Communication (b1)

Alice and Bob exchange their wallet addresses.

[Alice]’s console input:

bob_mona_address = 'MWsDkqHLonS5KfbRnRu3feByD9qkuj44Ye'
bob_ltc_address = 'LUAn5PWmsPavgz32mGkqsUuAKncftS37Jq'

[Bob]’s console input:

alice_mona_address = 'MPLx6eJS41da9bPsLLkHo35uY6KsHu7dXP'
alice_ltc_address = 'LXRAXRgPo84p58746zaBXUFFevCTYBPxgb'

3. Alice is initializing an atomic swap transaction using Monacoin

[Alice] has to prepare an atomic swap transaction

initial_transaction = mona_network.atomic_swap(
    sender_address=alice_mona_wallet.address,
    recipient_address=bob_mona_address,
    value=0.030,
)

initial_transaction.add_fee_and_sign(alice_mona_wallet)

initial_transaction.show_details()

{'contract': '63a61450314a793bf317665ecdc54c2e843bb106aeee158876a914fbed00c1502fded3dfa2524f8672ee013bb3f28f670465bab85bb17576a914a96a92963b7a65ac904875cfa5d535b3115888276888ac',
 'contract_address': 'PHVjh4aEgaY5DucNGT6xoFjLD1LAqo9SMu',
 'contract_transaction': '0100000001d4a61b33e849c8df64a2c839b878437a0ef055887ff0bf4279b8a805a2043b69010000006b483045022100a038a71fc3218c67e64804171b8a311397872fff51c85cbef81170570915946b02202385c01f3c4b06416108b6b856ca4f112e79ed74bc36766df4d994a696a7479401210240917aa65f12d8051abae7e8e98eea3b085a766a2dd7bd7f71c8121304cca2980000000002c0c62d000000000017a91461b1cbc5cd1b50e69e1c895d6cbcc94376c4ab3c87345e1401000000001976a914a96a92963b7a65ac904875cfa5d535b31158882788ac00000000',
 'fee': 0.00017655,
 'fee_per_kb': 0.0007881781818181818,
 'fee_per_kb_text': '0.00078818 MONA / 1 kB',
 'fee_text': '0.00017655 MONA',
 'locktime': datetime.datetime(2018, 10, 6, 13, 36, 37, 851140),
 'recipient_address': 'MWsDkqHLonS5KfbRnRu3feByD9qkuj44Ye',
 'refund_address': 'MPLx6eJS41da9bPsLLkHo35uY6KsHu7dXP',
 'secret': 'c480afb333623864901c968022a07dd93fe3c06f5684ea728b8113e17fa91bd9',
 'secret_hash': '50314a793bf317665ecdc54c2e843bb106aeee15',
 'size': 224,
 'size_text': '224 bytes',
 'transaction_address': 'a019e444e331ec843ae2d98b87073884e695dd08be06ba91f335af89dbe45473',
 'transaction_link': 'https://insight.electrum-mona.org/insight/tx/a019e444e331ec843ae2d98b87073884e695dd08be06ba91f335af89dbe45473',
 'value': 0.03,
 'value_text': '0.03000000 MONA'}

 initial_transaction.publish()
 'a019e444e331ec843ae2d98b87073884e695dd08be06ba91f335af89dbe45473'

We can check if the transaction exists by using the transaction_link from show_details() or by calling the mona_network.get_transaction(initial_transaction.address).

Check transaction in block explorer

4. Communication (b2)

[Alice] sends her transaction address a019e444e331ec843ae2d98b87073884e695dd08be06ba91f335af89dbe45473 and contract 63a61450314a793bf317665ecdc54c2e843bb106aeee158876a914fbed00c1502fded3dfa2524f8672ee013bb3f28f670465bab85bb17576a914a96a92963b7a65ac904875cfa5d535b3115888276888ac to Bob, so he can audit the transaction.

5. Contract audit (MONA)

[Bob] needs to create a contract in a network of coins he wants to receive (i.e. Alice’s network), in our case in Monacoin network. And also at this point Bob should validate if the data returned in the contract are correct.

alice_contract = mona_network.audit_contract(
    contract='63a61450314a793bf317665ecdc54c2e843bb106aeee158876a914fbed00c1502fded3dfa2524f8672ee013bb3f28f670465bab85bb17576a914a96a92963b7a65ac904875cfa5d535b3115888276888ac',
    transaction_address='a019e444e331ec843ae2d98b87073884e695dd08be06ba91f335af89dbe45473',
)
alice_contract.show_details()

{'confirmations': 9,
 'contract_address': 'PHVjh4aEgaY5DucNGT6xoFjLD1LAqo9SMu',
 'locktime': datetime.datetime(2018, 10, 6, 13, 36, 37),
 'recipient_address': 'MWsDkqHLonS5KfbRnRu3feByD9qkuj44Ye',
 'refund_address': 'MPLx6eJS41da9bPsLLkHo35uY6KsHu7dXP',
 'secret_hash': '50314a793bf317665ecdc54c2e843bb106aeee15',
 'transaction_address': 'a019e444e331ec843ae2d98b87073884e695dd08be06ba91f335af89dbe45473',
 'transaction_link': 'https://insight.electrum-mona.org/insight/tx/a019e444e331ec843ae2d98b87073884e695dd08be06ba91f335af89dbe45473',
 'value': 0.03,
 'value_text': '0.03000000 MONA'}

6. Participation (LTC)

[Bob] has to create a parallel transaction from point 3 but in his network (i.e. Litecoin network). We call it a participate_transaction.

participate_transaction = alice_contract.participate(
    symbol='LTC',
    sender_address=bob_ltc_wallet.address,
    recipient_address=alice_ltc_address,
    value=0.001,
)

participate_transaction.add_fee_and_sign(bob_ltc_wallet)

participate_transaction.show_details()

{'contract': '63a61450314a793bf317665ecdc54c2e843bb106aeee158876a91485c0522f6e23beb11cc3d066cd20ed732648a4e66704926db75bb17576a914621f617c765c3caa5ce1bb67f6a3e51382b8da296888ac',
 'contract_address': 'MSRzh2WrJ7o3ceSvCTxsuMk6i69kpWrtwS',
 'contract_transaction': '0100000001741a87828215c8bfeef3cfa70925ce91bca806f4f3dd931092f3b1727692504e000000008b483045022100bbd11530d3ea9cdf7b6385ff9aa884acdc04c8cdc96e182360ef5e69fb270512022054c0c5d2024878324af45b7ca5d81b19099e847976a0bbba2d23741a30f6eab401410431ab07973bbb5dbc6b7422fc7322abb5df15f77694c0b15b09a325996af47ddd887c7eaa72c656a71fcb333068956de7b3e2f15deaafc1d9285d779ca1b6a3f60000000002a08601000000000017a914cb4731b2c83362dcd05bba45e5f0ab8cd8642e4a876b730200000000001976a914621f617c765c3caa5ce1bb67f6a3e51382b8da2988ac00000000',
 'fee': 2.146e-05,
 'fee_per_kb': 8.415e-05,
 'fee_per_kb_text': '0.00008415 LTC / 1 kB',
 'fee_text': '0.00002146 LTC',
 'locktime': datetime.datetime(2018, 10, 5, 13, 56, 34, 8070),
 'recipient_address': 'LXRAXRgPo84p58746zaBXUFFevCTYBPxgb',
 'refund_address': 'LUAn5PWmsPavgz32mGkqsUuAKncftS37Jq',
 'secret': '',
 'secret_hash': '50314a793bf317665ecdc54c2e843bb106aeee15',
 'size': 256,
 'size_text': '256 bytes',
 'transaction_address': '09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa',
 'transaction_link': 'https://chainz.cryptoid.info/ltc/tx.dws?09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa.htm',
 'value': 0.001,
 'value_text': '0.00100000 LTC'}

participate_transaction.publish()
'09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa'

Check transaction on block explorer

7. Communication (b3)

[Bob] sends his transaction address 09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa and contract 63a61450314a793bf317665ecdc54c2e843bb106aeee158876a91485c0522f6e23beb11cc3d066cd20ed732648a4e66704926db75bb17576a914621f617c765c3caa5ce1bb67f6a3e51382b8da296888ac to Alice.

8. Contract audit (LTC)

[Alice] needs to audit the contract in a network of coins she wants to receive (i.e. Bob’s network), in our case on the Litecoin network. And also at this point Alice should validate if the data returned in the contract are correct

bob_contract = ltc_network.audit_contract(
    contract='63a61450314a793bf317665ecdc54c2e843bb106aeee158876a91485c0522f6e23beb11cc3d066cd20ed732648a4e66704926db75bb17576a914621f617c765c3caa5ce1bb67f6a3e51382b8da296888ac',
    transaction_address='09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa'
)

[Alice] can check the details of the contract

bob_contract.show_details()

{'confirmations': 1,
 'contract_address': 'MSRzh2WrJ7o3ceSvCTxsuMk6i69kpWrtwS',
 'locktime': datetime.datetime(2018, 10, 5, 13, 56, 34),
 'recipient_address': 'LXRAXRgPo84p58746zaBXUFFevCTYBPxgb',
 'refund_address': 'LUAn5PWmsPavgz32mGkqsUuAKncftS37Jq',
 'secret_hash': '50314a793bf317665ecdc54c2e843bb106aeee15',
 'transaction_address': '09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa',
 'transaction_link': 'https://chainz.cryptoid.info/ltc/tx.dws?09a60dc3fafe6ba058b2a140457df1c3b446602595d47deed641cb635ffd25aa.htm',
 'value': 0.001,
 'value_text': '0.00100000 LTC'}

9. First redeem transaction (LTC)

[Alice] can now collect coins she wants, thus she creates redeem transaction.

alice_redeem = bob_contract.redeem(secret=initial_transaction.show_details()['secret'], wallet=alice_ltc_wallet)
alice_redeem.add_fee_and_sign()

alice_redeem.show_details()

{'fee': 2.886e-05,
 'fee_per_kb': 8.415e-05,
 'fee_per_kb_text': '0.00008415 LTC / 1 kB',
 'fee_text': '0.00002886 LTC',
 'recipient_address': 'LXRAXRgPo84p58746zaBXUFFevCTYBPxgb',
 'size': 342,
 'size_text': '342 bytes',
 'transaction': '0100000001aa25fd5f63cb41d6ee7dd495256046b4c3f17d4540a1b258a06bfefac30da60900000000fdff0047304402201c8869d359b5599ecffd51a96f0a8799392c98c4e15242762ba455e37b1f5d6302203f2974e9afc8d641f9363167df48e5a845a8deba1381bf5a1b549ac04718a1ac01410459cdb91eb7298bc2578dc4e7ac2109ac3cfd9dc9818795c5583e720d2114d540724bf26b4541f683ff51968db627a04eecd1f5cff615b6350dad5fb595f8adf420c480afb333623864901c968022a07dd93fe3c06f5684ea728b8113e17fa91bd9514c5163a61450314a793bf317665ecdc54c2e843bb106aeee158876a91485c0522f6e23beb11cc3d066cd20ed732648a4e66704926db75bb17576a914621f617c765c3caa5ce1bb67f6a3e51382b8da296888ac00000000015a7b0100000000001976a91485c0522f6e23beb11cc3d066cd20ed732648a4e688ac00000000',
 'transaction_address': 'a5c027027c695f403fe570850e35ffd44bb28479ecaaee039372015fe0aae7b2',
 'transaction_link': 'https://chainz.cryptoid.info/ltc/tx.dws?a5c027027c695f403fe570850e35ffd44bb28479ecaaee039372015fe0aae7b2.htm',
 'value': 0.001,
 'value_text': '0.00100000 LTC'}

alice_redeem.publish()
'a5c027027c695f403fe570850e35ffd44bb28479ecaaee039372015fe0aae7b2'

Check transaction in block explorer

[Alice] should get litecoins just after redeem transaction is published.

10. Secret capture (LTC)

[Bob] should check if his contract has been already redeemed to be able to extract the secret from the redeem transaction.

contract_address = participate_transaction.show_details()['contract_address']
secret = ltc_network.extract_secret_from_redeem_transaction(contract_address)
secret
'c480afb333623864901c968022a07dd93fe3c06f5684ea728b8113e17fa91bd9'

11. Second redeem transaction (MONA)

[Bob] can now collect coins he wants, thus he creates redeem transaction.

bob_redeem = alice_contract.redeem(secret=secret, wallet=bob_mona_wallet)

bob_redeem.add_fee_and_sign()

bob_redeem.show_details()
{'fee': 0.00014787,
 'fee_per_kb': 0.0004801077777777778,
 'fee_per_kb_text': '0.00048011 MONA / 1 kB',
 'fee_text': '0.00014787 MONA',
 'recipient_address': 'MWsDkqHLonS5KfbRnRu3feByD9qkuj44Ye',
 'size': 309,
 'size_text': '309 bytes',
 'transaction': '01000000017354e4db89af35f391ba06be08dd95e6843807878bd9e23a84ec31e344e419a000000000e0483045022100d3e8f684e2bcdfe43a3f8ea6f6f77a97c7ebfe5e6ba3f280a078f18967d2b43a02204b40068e347e607438c893b83439099bf150f962a5b1009709d513732b4c6f0e0121028164de7b41f30fafac11350539035b38304def75c448d24178b6bc9ac902e95e20c480afb333623864901c968022a07dd93fe3c06f5684ea728b8113e17fa91bd9514c5163a61450314a793bf317665ecdc54c2e843bb106aeee158876a914fbed00c1502fded3dfa2524f8672ee013bb3f28f670465bab85bb17576a914a96a92963b7a65ac904875cfa5d535b3115888276888ac0000000001fd8c2d00000000001976a914fbed00c1502fded3dfa2524f8672ee013bb3f28f88ac00000000',
 'transaction_address': '5d6972cbb7ec034003e7880302d69b2d83b54eb89193a606ff26d7fbb253bba1',
 'transaction_link': 'https://insight.electrum-mona.org/insight/tx/5d6972cbb7ec034003e7880302d69b2d83b54eb89193a606ff26d7fbb253bba1',
 'value': 0.03,
 'value_text': '0.03000000 MONA'}

bob_redeem.publish()
'5d6972cbb7ec034003e7880302d69b2d83b54eb89193a606ff26d7fbb253bba1'

Check transaction in block explorer

[Bob] should get monacoins just after redeem transaction is published.

Ethereum Testnet

Assumptions

  • Alice wants to buy 0.5 ETH for 1000 Blockbusters Test tokens in Ethereum Kovan Testnet
  • Bob wants to buy 1000 Blockbusters Test tokens for 0.5 ETH in Ethereum Kovan Testnet
  • Both Alice and Bob have wallets in Ethereum Kovan network

1. Setup

Alice should initialize the network object, set her address, private key, amount of tokens to be swapped and the address of the token.

[Alice]’s console input:

from clove.network import EthereumTestnet
eth_test = EthereumTestnet()

address = '0x999F348959E611F1E9eab2927c21E88E48e6Ef45'
private_key = 'alice_private_key'

tokens_to_swap = '1000'
token_address = '0x53E546387A0d054e7FF127923254c0a679DA6DBf'

It is also possible to get the token data directly from the network object by the token symbol if the token is supported:

token = eth_test.get_token_by_symbol('BBT')
token_address = token.token_address

Bob should initialize the network object, set his address, private key and amount of ethers to be swapped.

[Bob]’s console input:

from clove.network import EthereumTestnet
eth_test = EthereumTestnet()

address = '0xd867f293Ba129629a9f9355fa285B8D3711a9092'
private_key = 'bob_private_key'

eth_to_swap = '0.5'

2. Communication (e1)

Alice and Bob exchange their wallet addresses.

[Alice]’s console input:

bob_address = '0xd867f293Ba129629a9f9355fa285B8D3711a9092'

[Bob]’s console input:

alice_address = '0x999F348959E611F1E9eab2927c21E88E48e6Ef45'

3. Token approval

To send tokens to an atomic swap contract Alice has to first approve that the tokens she owns can be spent by that contract.

approve_transaction = eth_test.approve_token(address, tokens_to_swap, token_address)
approve_transaction.sign(private_key)
approve_transaction.show_details()

{'contract_address': '0x7657Ca877Fac31D20528B473162E39B6E152fd2e',
 'data': '0x095ea7b30000000000000000000000007657ca877fac31d20528b473162e39b6e152fd2e00000000000000000000000000000000000000000000003635c9adc5dea00000',
 'gasprice': 20000000000,
 'nonce': 34,
 'r': 112426775415197512764524506063660144184257199595961926193168166347175765778579,
 's': 1927313746114385663128009448899947006587692267799486537632890580735710981604,
 'sender': '0x999f348959e611f1e9eab2927c21e88e48e6ef45',
 'sender_address': '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
 'startgas': 45576,
 'token_address': '0x53E546387A0d054e7FF127923254c0a679DA6DBf',
 'transaction_address': '0x40b8d435ff4bfbb202aed75dfc87f64e0d3da3838581b6635ae615e0454bd4fc',
 'v': 28,
 'value': Decimal('1000'),
 'value_text': '1000.000000000000000000 BBT'}

approve_transaction.publish()
'0x40b8d435ff4bfbb202aed75dfc87f64e0d3da3838581b6635ae615e0454bd4fc'

Check transaction on block explorer

4. Alice is initializing an atomic swap transaction using BBT token

initial_transaction = eth_test.atomic_swap(
    sender_address=address,
    recipient_address=bob_address,
    value=tokens_to_swap,
    token_address=token_address
)
initial_transaction.sign(private_key)
initial_transaction.show_details()

{'contract_address': '0x7657Ca877Fac31D20528B473162E39B6E152fd2e',
 'data': '0x52f50db7000000000000000000000000000000000000000000000000000000005acde5c48cebcb1af6fa5fddeb091f61f0af1c49a6de9922000000000000000000000000000000000000000000000000d867f293ba129629a9f9355fa285b8d3711a909200000000000000000000000053e546387a0d054e7ff127923254c0a679da6dbf00000000000000000000000000000000000000000000003635c9adc5dea00000',
 'gas_limit': None,
 'gasprice': 20000000000,
 'locktime': datetime.datetime(2018, 4, 11, 10, 39, 0, 535753),
 'nonce': 35,
 'r': 81080759208730988867907650750974367955166566527430658028938499115001735694910,
 'recipient_address': '0xd867f293Ba129629a9f9355fa285B8D3711a9092',
 'refund_address': '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
 's': 25371208205154004938960599477560107420234164093623357637201902103097079815422,
 'secret': 'c037026e2d0f3901c797d2414df30a4ce700d18055925f416e575635c5c2b7ac',
 'secret_hash': '8cebcb1af6fa5fddeb091f61f0af1c49a6de9922',
 'sender': '0x999f348959e611f1e9eab2927c21e88e48e6ef45',
 'sender_address': '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
 'startgas': 300000,
 'to': '0x7657ca877fac31d20528b473162e39b6e152fd2e',
 'token_address': '0x53E546387A0d054e7FF127923254c0a679DA6DBf',
 'transaction_address': '0x4cc2308652423a1b05712def62fe5183dfa507bd033941bdb40b56a258760840',
 'v': 27,
 'value': Decimal('1000'),
 'value_text': '1000.000000000000000000 BBT'}

initial_transaction.publish()
'0x4cc2308652423a1b05712def62fe5183dfa507bd033941bdb40b56a258760840'

Check transaction on block explorer

5. Communication (e2)

[Alice] sends her transaction address 0x4cc2308652423a1b05712def62fe5183dfa507bd033941bdb40b56a258760840 to Bob so he can audit created contract.

6. Contract audit (BBT token)

[Bob] needs to audit the contract in the network it was created in, in our case it’s Ethereum Testnet network. And also at this point Bob should validate if the data returned in the contract are correct.

alice_contract = eth_test.audit_contract('0x4cc2308652423a1b05712def62fe5183dfa507bd033941bdb40b56a258760840')
alice_contract.show_details()

{'contract_address': '0x7657Ca877Fac31D20528B473162E39B6E152fd2e',
 'locktime': datetime.datetime(2018, 4, 11, 10, 39),
 'recipient_address': '0xd867f293Ba129629a9f9355fa285B8D3711a9092',
 'refund_address': '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
 'secret_hash': '8cebcb1af6fa5fddeb091f61f0af1c49a6de9922',
 'token_address': '0x53E546387A0d054e7FF127923254c0a679DA6DBf',
 'transaction_address': '0x4cc2308652423a1b05712def62fe5183dfa507bd033941bdb40b56a258760840',
 'value': Decimal('1000'),
 'value_text': '1000.000000000000000000 BBT'}

7. Participation (ETH-TESTNET)

[Bob] has to create a parallel transaction from point 4 but for 0.5 ETH. We call it participate_transaction.

participate_transaction = alice_contract.participate(
    symbol='ETH-TESTNET',
    sender_address=address,
    recipient_address=alice_address,
    value=eth_to_swap
)

participate_transaction.sign(private_key)
participate_transaction.show_details()

{'contract_address': '0x9F7e5402ed0858Ea0C5914D44B900A42C89547B8',
 'data': '0xeb8ae1ed000000000000000000000000000000000000000000000000000000005acca1d68cebcb1af6fa5fddeb091f61f0af1c49a6de9922000000000000000000000000000000000000000000000000999f348959e611f1e9eab2927c21e88e48e6ef45',
 'gas_limit': 126221,
 'gasprice': 20000000000,
 'locktime': datetime.datetime(2018, 4, 10, 11, 36, 54, 224171),
 'nonce': 18,
 'r': 10117394961799586109544014237169747431096329877057063230289022533801441532789,
 'recipient_address': '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
 'refund_address': '0xd867f293Ba129629a9f9355fa285B8D3711a9092',
 's': 34556783084242874049490624129921763496945955547455400337813271950949674389178,
 'secret_hash': '8cebcb1af6fa5fddeb091f61f0af1c49a6de9922',
 'sender': '0xd867f293ba129629a9f9355fa285b8d3711a9092',
 'sender_address': '0xd867f293Ba129629a9f9355fa285B8D3711a9092',
 'startgas': 126221,
 'to': '0x9f7e5402ed0858ea0c5914d44b900a42c89547b8',
 'transaction_address': '0xc9b2bf9b67dcfea39dea71b3416922adfcae23f6410be7d109fb9df2e1c0695f',
 'v': 28,
 'value': Decimal('0.5'),
 'value_text': '0.500000000000000000 ETH'}

participate_transaction.publish()
'0xc9b2bf9b67dcfea39dea71b3416922adfcae23f6410be7d109fb9df2e1c0695f'

Check transaction on block explorer

8. Communication (e3)

[Bob] sends his transaction address 0xc9b2bf9b67dcfea39dea71b3416922adfcae23f6410be7d109fb9df2e1c0695f to Alice.

9. Contract audit (ETH-TESTNET)

[Alice] needs to audit the contract in the network it was created in, in our case it’s Ethereum Testnet network. And also at this point Alice should validate if the data returned in the contract are correct.

bob_contract = eth_test.audit_contract(
    '0xc9b2bf9b67dcfea39dea71b3416922adfcae23f6410be7d109fb9df2e1c0695f'
)
bob_contract.show_details()

{'contract_address': '0x9F7e5402ed0858Ea0C5914D44B900A42C89547B8',
 'locktime': datetime.datetime(2018, 4, 10, 11, 36, 54),
 'recipient_address': '0x999F348959E611F1E9eab2927c21E88E48e6Ef45',
 'refund_address': '0xd867f293Ba129629a9f9355fa285B8D3711a9092',
 'secret_hash': '8cebcb1af6fa5fddeb091f61f0af1c49a6de9922',
 'transaction_address': '0xc9b2bf9b67dcfea39dea71b3416922adfcae23f6410be7d109fb9df2e1c0695f',
 'value': Decimal('0.5'),
 'value_text': '0.500000000000000000 ETH'}

10. First redeem transaction (ETH-TESTNET)

[Alice] can now collect coins she wants, thus she creates redeem transaction.

alice_redeem = bob_contract.redeem(secret=initial_transaction.show_details()['secret'])
alice_redeem.sign(private_key)

alice_redeem.show_details()

{'data': '0xeda1122cc037026e2d0f3901c797d2414df30a4ce700d18055925f416e575635c5c2b7ac',
 'gasprice': 20000000000,
 'hash': '0x80addbc1b1ff0cf32949c78cde0dc4347f1a81e7f510fd266aa934523c92c2c1',
 'nonce': 36,
 'r': 59319998726546023363151651169655572196637192178004534224886682741537229136353,
 's': 49667378228500740364784037188336222900603288337407062594007817473604371090679,
 'sender': '0x999f348959e611f1e9eab2927c21e88e48e6ef45',
 'startgas': 100000,
 'to': '0x9f7e5402ed0858ea0c5914d44b900a42c89547b8',
 'v': 28,
 'value': Decimal('0.5'),
 'value_text': '0.500000000000000000 ETH'}

alice_redeem.publish()
'0x80addbc1b1ff0cf32949c78cde0dc4347f1a81e7f510fd266aa934523c92c2c1'

Check transaction on block explorer

[Alice] will get ether just after redeem transaction is published.

11. Secret capture (ETH-TESTNET)

[Bob] should extract the secret from the redeem transaction. For this operation (find_redeem_transaction) an Etherscan API key is required - read more

alice_redeem_tx_hash = participate_transaction.find_redeem_transaction()
secret = eth_test.extract_secret_from_redeem_transaction(alice_redeem_tx_hash)
secret
'c037026e2d0f3901c797d2414df30a4ce700d18055925f416e575635c5c2b7ac'

12. Second redeem transaction (BBT token)

[Bob] can now collect tokens he wants, thus he creates redeem transaction.

bob_redeem = alice_contract.redeem(secret)
bob_redeem.sign(private_key)

bob_redeem.show_details()

{'data': '0xeda1122cc037026e2d0f3901c797d2414df30a4ce700d18055925f416e575635c5c2b7ac',
 'gasprice': 20000000000,
 'hash': '0x4fd41289b816f6122e59a0759bd10441ead75d550562f4b3aad2fddc56eb3274',
 'nonce': 19,
 'r': 65751206609566246138168255228214505208801025362644939199208252280848271690158,
 's': 45667062183625152271430540771543035424773489029161348648874675951038677865195,
 'sender': '0xd867f293ba129629a9f9355fa285b8d3711a9092',
 'startgas': 100000,
 'to': '0x7657ca877fac31d20528b473162e39b6e152fd2e',
 'v': 27,
 'value': Decimal('1000'),
 'value_text': '1000.000000000000000000 BBT'}

bob_redeem.publish()
'0x4fd41289b816f6122e59a0759bd10441ead75d550562f4b3aad2fddc56eb3274'

Check transaction on block explorer

[Bob] will get BBT tokens just after redeem transaction is published.