def main(self): """ to run: kosmos 'j.clients.tfchain.test(name="threebot_name_transfer")' """ # create a tfchain client for devnet c = j.clients.tfchain.new("mydevclient", network_type="DEV") # or simply `c = j.tfchain.clients.mydevclient`, should the client already exist # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network) explorer_client = TFChainExplorerGetClientStub() explorer_client.hash_add( "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a", '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"066c03b5cf6db18edd6013591ae6292e8a04f1cc18fc6f0a0f3946d40bb087b3","height":3628,"parent":"761af2728b6f07bbccf4ddaf330c0bb1465246f6fe25fbfb9989129b69fbd899","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"670045cf43421b21577c27613569b65ba0cec613ae5437ee15dc0eea95241cbc","fulfillment":{"type":1,"data":{"publickey":"ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97","signature":"e5a47b166eb6724ca7a72b5ddaeff287ebdde09751ed10e8850d320744afc5f45e59aa66e2cc4dc45ff593a0eea696c4e780b81636a1ce748c7149a9ee0ba807"}}},{"parentid":"1d686b8dfe44dfbfea55f327a52d9701a52938cb2c829f709dfb8059bc0e5f87","fulfillment":{"type":1,"data":{"publickey":"ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa","signature":"5ce7a10373214d269837e9c176ec806469d2b80f200f9ee961c63553b6ee200f88958293a571889f26b2b52664f3c9ff2441eaf8ed61830b51d640003b06fb00"}}}],"coinoutputs":[{"value":"501000000000","condition":{"type":1,"data":{"unlockhash":"0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55"}}},{"value":"198000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"200000000000","condition":{"type":1,"data":{"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"}},"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"},{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}},"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}],"coinoutputids":["4b43906584620e8a13d98a917d424fb154dd1222a72b886a887c416b2a9120f5","19d4e81d057b4c93a7763f3dfe878f6a37d6111a3808b93afff4b369de0f5376"],"coinoutputunlockhashes":["0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55","014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"0b5d7509e467b943af12db2d73ddb78a5ec8cfdf64c3c6ecacb2de4af68bdc4d","height":33,"parent":"40e281daee6f113b788d64b8247381c36fe4885233a7475c9be2cce852e1696e","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"a3c8f44d64c0636018a929d2caeec09fb9698bfdcbfa3a8225585a51e09ee563","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"e5b69be3b385f0a33f7978e0d6af30cf37c975bbb99d0f3d06f199cd579d3e6854f6cb398c88082e438c89d11d04de0e7d3b2876e250d4ba8ae457f88547f605"}}}],"coinoutputs":[{"value":"1000000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99998999000000000","condition":{"type":1,"data":{"unlockhash":"01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"100000000000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"coinoutputids":["75f297550acfa48490c21490f82c3c308326c16f950e17ef3a286486065a51b8","6d157a1eb23cadde122192869bc51e2a0fe44a2d8aba898cbdda8b7218a0f8cb"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"1b144b89c4b65cc67416e27286e802c50f78bc7326b4b0e5f6f967f99cc39419","height":200,"parent":"68e3886c9a4c59dea8c7a0eb138ede0e83716b995fd8ebfa5dfc766bfb349565","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"6d157a1eb23cadde122192869bc51e2a0fe44a2d8aba898cbdda8b7218a0f8cb","fulfillment":{"type":1,"data":{"publickey":"ed25519:00bde9571b30e1742c41fcca8c730183402d967df5b17b5f4ced22c677806614","signature":"05c72055d4cca6d8620fd7453c89ac8deaf92c38e366604dc6405cb097321b74e2e5f7ece15b440f4af5721b8aa6ea1f57f4fce44d2a2c6c0fb7a1e068a0480d"}}}],"coinoutputs":[{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99998498000000000","condition":{"type":1,"data":{"unlockhash":"0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99998999000000000","condition":{"type":1,"data":{"unlockhash":"01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"}},"unlockhash":"01f68299b26a89efdb4351a61c3a062321d23edbc1399c8499947c1313375609adbbcd3977363c"}],"coinoutputids":["1d686b8dfe44dfbfea55f327a52d9701a52938cb2c829f709dfb8059bc0e5f87","e27ed8bbe45177fafdfd7d21394ff483b8bde24f551dd927a046a0b7c37ec228"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"5ab2604c7d54dd9ea39d829724e46deb8bbf2889d8627a3bb3b57907c6f4dff4","height":1433,"parent":"6b9fdad35096c5a84dcdb6e3e9ec2a8c7562f567e05b1207a7f9330ed51582bb","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"e27ed8bbe45177fafdfd7d21394ff483b8bde24f551dd927a046a0b7c37ec228","fulfillment":{"type":1,"data":{"publickey":"ed25519:41e84f3b0f6a06dd7e45ded4d0e227869725355b73906b82d9e3ffc0b6b01416","signature":"47a4d1a6aeb7403ea5c2cbcc26f84bb1964aadcb8765696db4a623694991f794663b860898db53401dd4324477c43f9fff177b74909201a03e131c2cd885cc0d"}}}],"coinoutputs":[{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99997997000000000","condition":{"type":1,"data":{"unlockhash":"0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99998498000000000","condition":{"type":1,"data":{"unlockhash":"0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"}},"unlockhash":"0161fbcf58efaeba8813150e88fc33405b3a77d51277a2cdf3f4d2ab770de287c7af9d456c4e68"}],"coinoutputids":["b90422bad2dffde79f0a46bd0a41055cf7974b080e115d76f69891ca31d31f11","f386312779f382f16fa836038b3d25536b928ba88ae1afa1f8c0e8dc25c0ba16"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"81d81b413fc8af3e528478e639d5a6e999e5e96611593cd2458b4d2d7abc3880","height":1433,"parent":"6b9fdad35096c5a84dcdb6e3e9ec2a8c7562f567e05b1207a7f9330ed51582bb","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"f386312779f382f16fa836038b3d25536b928ba88ae1afa1f8c0e8dc25c0ba16","fulfillment":{"type":1,"data":{"publickey":"ed25519:4e42a2fcfc0963d6fa7bb718fd088d9b6544331e8562d2743e730cdfbedeb55a","signature":"4abae694cf6a6408eca6f034ea2ec6930b9a73303c3e70d3444cf36a9966b0c4cc1b65168c23640affb5bdeae539ea583d42da52c58d21f59b71c288b3faef0e"}}}],"coinoutputs":[{"value":"2000000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}},{"value":"99995996000000000","condition":{"type":1,"data":{"unlockhash":"0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"}}}],"minerfees":["1000000000"],"arbitrarydata":"Zm9vYmFy"}},"coininputoutputs":[{"value":"99997997000000000","condition":{"type":1,"data":{"unlockhash":"0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"}},"unlockhash":"0137f6f647a3c8019f6ae215ed09902c308efbf555b3520d2112d2b18cb577e40804d6fc5fafd2"}],"coinoutputids":["d1f74e90eba8095e78f08a6284c7b76d4cda86b06ac742062d6e0e02dc4607eb","1edccdb04100ffd05d97431b6798533fa57dc7ed1ea58c75f0f445fb64442d6e"],"coinoutputunlockhashes":["014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a","0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":["039e16ed27b2dfa3a5bbb1fa2b5f240ba7ff694b34a52bfc5bed6d4c3b14b763c011d7503ccb3a"],"unconfirmed":false}', ) explorer_client.hash_add( "018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd", '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"066c03b5cf6db18edd6013591ae6292e8a04f1cc18fc6f0a0f3946d40bb087b3","height":3628,"parent":"761af2728b6f07bbccf4ddaf330c0bb1465246f6fe25fbfb9989129b69fbd899","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"670045cf43421b21577c27613569b65ba0cec613ae5437ee15dc0eea95241cbc","fulfillment":{"type":1,"data":{"publickey":"ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97","signature":"e5a47b166eb6724ca7a72b5ddaeff287ebdde09751ed10e8850d320744afc5f45e59aa66e2cc4dc45ff593a0eea696c4e780b81636a1ce748c7149a9ee0ba807"}}},{"parentid":"1d686b8dfe44dfbfea55f327a52d9701a52938cb2c829f709dfb8059bc0e5f87","fulfillment":{"type":1,"data":{"publickey":"ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa","signature":"5ce7a10373214d269837e9c176ec806469d2b80f200f9ee961c63553b6ee200f88958293a571889f26b2b52664f3c9ff2441eaf8ed61830b51d640003b06fb00"}}}],"coinoutputs":[{"value":"501000000000","condition":{"type":1,"data":{"unlockhash":"0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55"}}},{"value":"198000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"200000000000","condition":{"type":1,"data":{"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"}},"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"},{"value":"500000000000","condition":{"type":1,"data":{"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}},"unlockhash":"014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"}],"coinoutputids":["4b43906584620e8a13d98a917d424fb154dd1222a72b886a887c416b2a9120f5","19d4e81d057b4c93a7763f3dfe878f6a37d6111a3808b93afff4b369de0f5376"],"coinoutputunlockhashes":["0186cea43fa0d303a6379ae76dd79f014698956fb982751549e3ff3844b23fa9551c1725470f55","014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},{"id":"d0d290dccddaf086708e4163eacd420bfbaa7acb77deea97c6a8792a139f6e7e","height":3583,"parent":"ca746d80740ff45f6e7f0d6c8b6278b35b1040b4e21baaf41bd03cd3a7a176be","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"1edccdb04100ffd05d97431b6798533fa57dc7ed1ea58c75f0f445fb64442d6e","fulfillment":{"type":1,"data":{"publickey":"ed25519:7469d51063cdb690cc8025db7d28faadc71ff69f7c372779bf3a1e801a923e02","signature":"6f38467bb4ca23900e424d5ac2066a09b61fe9d9ae84a4231755063f591d04711f0a5ab11b60b42c2c32a8e7f73fc1cc1cb0073b036bc417ed504a8ef5f25402"}}}],"coinoutputs":[{"value":"200000000000","condition":{"type":1,"data":{"unlockhash":"018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd"}}},{"value":"99995795000000000","condition":{"type":1,"data":{"unlockhash":"01f706dcbb9f0cb1e97d891ada3a133f68612ebff948c5bbae7851108a65dab7782907eecd86be"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99995996000000000","condition":{"type":1,"data":{"unlockhash":"0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"}},"unlockhash":"0173f82c3ee74286c33fee8d883a7e9e759c6230b9e4e956ef233d7202bde69da45054270eef99"}],"coinoutputids":["670045cf43421b21577c27613569b65ba0cec613ae5437ee15dc0eea95241cbc","984555e190d58dc752aad81b0a6cf6194fa5bf89b8614efcd9604d138a8953bc"],"coinoutputunlockhashes":["018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd","01f706dcbb9f0cb1e97d891ada3a133f68612ebff948c5bbae7851108a65dab7782907eecd86be"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}', ) explorer_client.chain_info = '{"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1}' explorer_client.hash_add( "552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e", '{"hashtype":"blockid","block":{"minerpayoutids":["468db689f752414702ef3a5aa06238f03a4539434a61624b3b8a0fb5dc38a211"],"transactions":[{"id":"2396f8e57bbb9b22bd1d749d5de3fd532ea6886e9660a556a13571d701d83e27","height":3644,"parent":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["f683e7319659c61f54e93546bc41b57c5bffe79de26c06ec7371034465804c81"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"47db4274551b0372564f8d1ab89c596428f00e460c0b416327e53983c8765198","timestamp":1549012665,"pobsindexes":{"BlockHeight":3643,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}', ) explorer_client.hash_add( "039e16ed27b2dfa3a5bbb1fa2b5f240ba7ff694b34a52bfc5bed6d4c3b14b763c011d7503ccb3a", '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"4c70a0406f36cf354edf87642df3f34568fd0a89c052a81d11cc6e4f8fbf685e","height":45,"parent":"f7b78b17d581ff9e58ffbcce1701d4dcadb0781590ca68e839def0dc98b0360a","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"7d4a100fc3bc08b2bdd1284c17260dd2bd6b55fd6c1429dbbd683bf362d92b50","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"c34b8ca1ab08930bc68d61026af504d62d8a8bbda9b79ae01a387560fba22d39b12021e16566732b742ea686f997b3c19c807523797cdc0d74a4d25123691004"}}},{"parentid":"83503f9cea00d562e0460eace93159a4c4dd00df4703c96947e81885b46da04c","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"f6eea681a259baf14433ac55b4293b22ca2056810ee8fed2129039224d14558f54ca58c6d96e9885cb20ecdf7e64ba81d1a83c6e9a42bf9464287fa6359d360c"}}},{"parentid":"578aa43de72b42b4f4547c5ddc7f61736b1cac206e1789bc89fcd9333cf3d1f3","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"a0521d14dfe4a0c9b8b57ed361d738b48b6a8346097246effe0b4ee67b6fecbc3a90e4671ddc0b164f6c2839df249bb5998f10216a4a674ba8d24b8ad6bdf808"}}},{"parentid":"5a1454762e6895431e1b9e4e435e4d0ad60a3881843ac46b88e220771055ca87","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"900e7868780e67bcb68af3ec6976e84289850d0db59210d4689b1c0e2deb3164b9e93eb9ee5a38850f2319463b0845163e1eee443d7b645c59485c2aa0837707"}}},{"parentid":"c04ebebe17a1759457eecaf4d5d33f5ddbe8d154b0be1606f05bc8fd02ab9cd4","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"e992b1cd3347b5362e820166d5929de7c682130c7143fc4c9ff3156f5d44110753687697a0154a2043290b3f022e2537f3e3a6807caf9150f8c255d74e386d0a"}}}],"coinoutputs":[{"value":"42000000000","condition":{"type":4,"data":{"unlockhashes":["01ffd7c884aa869056bfb832d957bb71a0005fee13c19046cebec84b3a5047ee8829eab070374b","014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a"],"minimumsignaturecount":1}}},{"value":"7000000000","condition":{"type":1,"data":{"unlockhash":"01972837ee396f22f96846a0c700f9cf7c8fa83ab4110da91a1c7d02f94f28ff03e45f1470df82"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"},{"value":"10000000000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"coinoutputids":["29152fe03a2c8782fcbd670579686088c52be83fa3870f5f0788073d97fb5fb2","0fc9b16bb180cd8f8a7144d65e6c8fca66994a4ccaee42e324289d4039ab2841"],"coinoutputunlockhashes":["039e16ed27b2dfa3a5bbb1fa2b5f240ba7ff694b34a52bfc5bed6d4c3b14b763c011d7503ccb3a","01972837ee396f22f96846a0c700f9cf7c8fa83ab4110da91a1c7d02f94f28ff03e45f1470df82"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}', ) # add threebot records: explorer_client.threebot_record_add( ThreeBotRecord( identifier=3, names=[BotName(value=s) for s in ["foorbar", "chatbot.example"]], addresses=[NetworkAddress(address=s) for s in ["example.org", "127.0.0.1"]], public_key=PublicKey.from_json("ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa"), expiration=1552581420, ) ) explorer_client.threebot_record_add( ThreeBotRecord( identifier=5, names=[], addresses=[NetworkAddress(address=s) for s in ["bot.example.org"]], public_key=PublicKey.from_json("ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97"), expiration=1552585420, ) ) c._explorer_get = explorer_client.explorer_get c._explorer_post = explorer_client.explorer_post # the devnet genesis seed is the seed of the wallet, # which receives all block stakes and coins in the genesis block of the tfchain devnet DEVNET_GENESIS_SEED = "image orchard airport business cost work mountain obscure flee alpha alert salmon damage engage trumpet route marble subway immune short tide young cycle attract" # create a new devnet wallet w = c.wallets.new("mywallet", seed=DEVNET_GENESIS_SEED) # we create a new wallet using an existing seed, # such that our seed is used and not a new randomly generated seed # a tfchain (JS) wallet uses the underlying tfchain client for all its # interaction with the tfchain network assert w.network_type == "DEV" # getting the balance of a wallet is as easy as getting the 'balance' property balance = w.balance # the available and locked tokens can be easily checked assert str(balance.available) == "3698" assert str(balance.locked) == "0" # assert the addresses are correct assert w.addresses == [ "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a", "018f5a43327fb865843808ddf549f1b1c06376e07195423778751056be626841f42dcf25a593fd", ] # transfering a name is easy as well: result = w.threebot.name_transfer( sender=3, # identifier of sender 3Bot receiver=5, # identifier of receiver 3Bot names=["foobar", "chatbot.example"], # names to be transfered from sender to receiver 3Bot ) assert result.submitted # we expect the transaction to be submitted expected_transaction = { "version": 146, "data": { "sender": { "id": 3, "signature": "e1b1bb0f6f9493b17f8959d2ff67741eee0642737c277e46644e2902e805866036af2ebf8ece2c4eb02539f2f0de49679231959d677f86ff05c19bc1f6c2eb00", }, "receiver": { "id": 5, "signature": "be7f8a47a1de99a5aaff1684c5973d50d3e1777c271309b08175b993802d4b19980a38c7d6d59362bff542cced12818d72745405f15ed9170319020a27aae30a", }, "names": ["foobar", "chatbot.example"], "txfee": "1000000000", "coininputs": [ { "parentid": "19d4e81d057b4c93a7763f3dfe878f6a37d6111a3808b93afff4b369de0f5376", "fulfillment": { "type": 1, "data": { "publickey": "ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa", "signature": "47d76c8cc278c1077574d0de6aaca6c13414bbf1c13f4f97cecb7ac1a19763eb9e0cf7c2584a8ade4bc7a8f4e220aa3b5d021ffd092af6dc8a07760a21e2e101", }, }, } ], "refundcoinoutput": { "value": "97000000000", "condition": { "type": 1, "data": { "unlockhash": "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a" }, }, }, }, } # ensure our transaction is as expected assert result.transaction.json() == expected_transaction # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == expected_transaction # if no names to be transfered are defined, a ValueError is raised with pytest.raises(ValueError): w.threebot.name_transfer(sender=3, receiver=5, names=[]) # if names are defined to be transfered but one of the two 3Bots do no exist, # an j.clients.tfchain.errors.ThreeBotNotFound will be raised with pytest.raises(j.clients.tfchain.errors.ThreeBotNotFound): w.threebot.name_transfer(sender=2, receiver=5, names=["foobar"]) with pytest.raises(j.clients.tfchain.errors.ThreeBotNotFound): w.threebot.name_transfer(sender=3, receiver=4, names=["foobar"]) # make our receiver 3Bot expired explorer_client.threebot_record_add( ThreeBotRecord( identifier=5, names=[], addresses=[NetworkAddress(address=s) for s in ["bot.example.org"]], public_key=PublicKey.from_json("ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97"), expiration=1549012664, ), force=True, ) # if the receiver 3Bot is inactive, an error will be raised with pytest.raises(j.clients.tfchain.errors.ThreeBotInactive): w.threebot.name_transfer(sender=3, receiver=5, names=["foobar"]) # make our sender 3Bot expired explorer_client.threebot_record_add( ThreeBotRecord( identifier=3, names=[BotName(value=s) for s in ["foorbar", "chatbot.example"]], addresses=[NetworkAddress(address=s) for s in ["example.org", "127.0.0.1"]], public_key=PublicKey.from_json("ed25519:64ae81a176302ea9ea47ec673f105da7a25e52bdf0cbb5b63d49fc2c69ed2eaa"), expiration=1549012664, ), force=True, ) # if the sender and receiver 3Bots are inactive, an error will be raised with pytest.raises(j.clients.tfchain.errors.ThreeBotInactive): w.threebot.name_transfer(sender=3, receiver=5, names=["foobar"]) # make our receiver 3Bot active again explorer_client.threebot_record_add( ThreeBotRecord( identifier=5, names=[], addresses=[NetworkAddress(address=s) for s in ["bot.example.org"]], public_key=PublicKey.from_json("ed25519:bdea9aff09bcdc66529f6e2ef1bb763a3bab83ce542e8673d97aeaed0581ad97"), expiration=1552585420, ), force=True, ) # if the sender 3Bot is inactive, an error will be raised with pytest.raises(j.clients.tfchain.errors.ThreeBotInactive): w.threebot.name_transfer(sender=3, receiver=5, names=["foobar"])
def main(self): """ to run: js_shell 'j.clients.tfchain.test(name="atomicswap_participate")' """ # create a tfchain client for devnet c = j.clients.tfchain.new("mytestclient", network_type="TEST") # or simply `c = j.tfchain.clients.mytestclient`, should the client already exist # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network) explorer_client = TFChainExplorerGetClientStub() # add the blockchain info explorer_client.chain_info = '{"blockid":"583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc","difficulty":"29305","estimatedactivebs":"2067","height":16922,"maturitytimestamp":1549649615,"target":[0,2,60,124,18,9,53,143,255,130,219,75,17,252,30,24,177,101,116,228,26,221,54,224,30,251,45,78,1,199,78,60],"totalcoins":"0","arbitrarydatatotalsize":4351,"minerpayoutcount":17006,"transactioncount":17547,"coininputcount":635,"coinoutputcount":1228,"blockstakeinputcount":16922,"blockstakeoutputcount":16923,"minerfeecount":624,"arbitrarydatacount":573}' explorer_client.hash_add( '583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc', '{"hashtype":"blockid","block":{"minerpayoutids":["eb538b38d8fcf7b0ef037eccf8cab1096c2b98031311453c150b2b150c483941"],"transactions":[{"id":"92132a65558684f154a56232acf9b7dd1e003d0f3ebdb2c4b44494d3c5e7f658","height":16922,"parent":"583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ca1da3d88904a532692ad2bb67122747eea4d91ead119043253ecb34410bbcc3","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"120c7bdf823a45fde303a725a1d757b3ece975abcd326ec036c056c6499b6de6cd798f18f8dff8c7adebcf19901e358609e675871335a71678c17de3e1dadb04"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["615f6f9d28d97082b423de7a878830b739b8fc4737c7ed20d3923a0019dbaed6"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"35879735f395c25fa7c0366bec7002f960798517e5335b5f27348c3a1b1923d4","timestamp":1549649728,"pobsindexes":{"BlockHeight":16921,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ca1da3d88904a532692ad2bb67122747eea4d91ead119043253ecb34410bbcc3","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"120c7bdf823a45fde303a725a1d757b3ece975abcd326ec036c056c6499b6de6cd798f18f8dff8c7adebcf19901e358609e675871335a71678c17de3e1dadb04"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"583266f598044ebd971110bd03510e950361c22b4ed818e7644b6d59c36fd5bc","difficulty":"29305","estimatedactivebs":"2067","height":16922,"maturitytimestamp":1549649615,"target":[0,2,60,124,18,9,53,143,255,130,219,75,17,252,30,24,177,101,116,228,26,221,54,224,30,251,45,78,1,199,78,60],"totalcoins":"0","arbitrarydatatotalsize":4351,"minerpayoutcount":17006,"transactioncount":17547,"coininputcount":635,"coinoutputcount":1228,"blockstakeinputcount":16922,"blockstakeoutputcount":16923,"minerfeecount":624,"arbitrarydatacount":573},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}' ) # add the wallet info explorer_client.hash_add( '01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0', '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"bca044302e018e67600bd0bd3223ae8dbb702eb528e73d6cfa9d057d4f73b03a","height":16911,"parent":"b4882a0b8632396a9c5d83a5c8684ab76736f4bff6d971795ed7334fac8aa339","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"357451c3f3a15f6150aedede9d5228ec5dfc2d32c9b62c2a46128533a7845c72","fulfillment":{"type":1,"data":{"publickey":"ed25519:fdb2e1b898dda304f748c0ff812a24729b2aafd344512079ab778eb368b18645","signature":"bd9dd36e86c08a5990ad5282d1079705c3a4b1cf3896e96791aa7db97002d5eb002c50467f45bd3ac1086292932cd2ab53c91b2e8bb74b9d9c9c0d558082ef08"}}}],"coinoutputs":[{"value":"51000000000","condition":{"type":1,"data":{"unlockhash":"01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0"}}},{"value":"99994187000000000","condition":{"type":1,"data":{"unlockhash":"0183841ae8952a2ba72db0d6fce6208df70f2a936ee589ff852e06b20af48b40489572b1a69b2a"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"99994239000000000","condition":{"type":1,"data":{"unlockhash":"019bb005b78a47fd084f4f3a088d83da4fadfc8e494ce4dae0d6f70a048a0a745d88ace6ce6f1c"}},"unlockhash":"019bb005b78a47fd084f4f3a088d83da4fadfc8e494ce4dae0d6f70a048a0a745d88ace6ce6f1c"}],"coinoutputids":["753aaeaa0c9e6c9f1f8da1974c83d8ca067ad536f464a2e2fc038bbd0404d084","8c8dbd70c6eb2d5d181aa5ae430f2cc86e038b92e45dd6f6d5a28400efad4511"],"coinoutputunlockhashes":["01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0","0183841ae8952a2ba72db0d6fce6208df70f2a936ee589ff852e06b20af48b40489572b1a69b2a"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}' ) # override internal functionality, as to use our stub client c._explorer_get = explorer_client.explorer_get c._explorer_post = explorer_client.explorer_post # a wallet is required to initiate an atomic swap contract w = c.wallets.new( "mytestwallet", seed= 'remain solar kangaroo welcome clean object friend later bounce strong ship lift hamster afraid you super dolphin warm emotion curve smooth kiss stem diet' ) # money is required to be available in the wallet assert str(w.balance.available) == '51' # a participation atomic swap contract can be created and signed as follows: result = w.atomicswap.participate( initiator= '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c', amount=50, secret_hash= '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba', submit=False) # submit=True is the default assert not result.submitted assert result.transaction.is_fulfilled() # the contract is returned as part of the result assert str(result.contract.amount) == '50' assert str( result.contract.sender ) == '01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0' assert str( result.contract.receiver ) == '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c' assert result.contract.refund_timestamp > 1549649728 assert result.contract.secret_hash == '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba' # one would than use `w.transaction_sign(result.transaction)` to submit it for real # however, usually an atomic swap contract is participated as follows: result = w.atomicswap.participate( initiator= '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c', amount=50, secret_hash= '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba') assert result.submitted # the contract is returned as part of the result assert str(result.contract.amount) == '50' assert str( result.contract.sender ) == '01b73c4e869b6167abe6180ebe7a907f56e0357b4a2f65eb53d22baad84650eb62fce66ba036d0' assert str( result.contract.receiver ) == '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c' assert result.contract.refund_timestamp > 1549649728 assert result.contract.secret_hash == '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba' # ensure our contract was submitted transaction = explorer_client.posted_transaction_get(result.transaction.id) contract = AtomicSwapContract(transaction.coin_outputs[0], unspent=True) assert contract == result.contract # and ensure the transaction is fully signed for ci in transaction.coin_inputs: assert len(ci.fulfillment.signature.value) == 64 # FYI: a contract's amount has to be greater than the network's minimum miner fee, # while tfchain does allow it, this client will raise an exception when you # do try to give a value equal to or less than the networks' miner fee. # This because such a contract cannot be redeemed or refunded. with pytest.raises(tfchain.errors.AtomicSwapInsufficientAmountError): w.atomicswap.participate( initiator= '01746b199781ea316a44183726f81e0734d93e7cefc18e9a913989821100aafa33e6eb7343fa8c', amount=c.minimum_miner_fee - '0.000000001 TFT', secret_hash= '4163d4b31a1708cd3bb95a0a8117417bdde69fd1132909f92a8ec1e3fe2ccdba')
def main(self): """ to run: js_shell 'j.clients.tfchain.test(name="atomicswap_initiate")' """ # create a tfchain client for devnet c = j.clients.tfchain.new("mytestclient", network_type="TEST") # or simply `c = j.tfchain.clients.mytestclient`, should the client already exist # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network) explorer_client = TFChainExplorerGetClientStub() # add the blockchain info explorer_client.chain_info = '{"blockid":"5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8","difficulty":"30203","estimatedactivebs":"2365","height":16639,"maturitytimestamp":1549646167,"target":[0,2,43,120,39,20,204,42,102,32,125,110,53,77,39,71,99,124,13,223,197,154,115,42,126,62,185,120,208,177,21,190],"totalcoins":"0","arbitrarydatatotalsize":4328,"minerpayoutcount":16721,"transactioncount":17262,"coininputcount":633,"coinoutputcount":1225,"blockstakeinputcount":16639,"blockstakeoutputcount":16640,"minerfeecount":622,"arbitrarydatacount":572}' explorer_client.hash_add('5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8', '{"hashtype":"blockid","block":{"minerpayoutids":["84b378d60cbdd78430b39c8eddf226119b6f28256388557dd15f0b046bf3c3ed"],"transactions":[{"id":"9aec9f849e35f0bdd14c5ea9daed20c8fbfa09f5a6771bb46ce787eb7e2b00a0","height":16639,"parent":"5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"144b2b7711fda335cdae5865ab3729d641266087bc4e088d9fba806345045903","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"f09af1c62026aed18d1d8f80e5a7bd4947a6cb5b6b69097c5b10cb983f0d729662c511a4852fa63690884e2b5c600e3935e08b81aaa757d9f0eb740292ec8309"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["83aa29b3e77f703526e28fbc0d2bfcf2b66c06b665e11cb5535b9575fd0e8105"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"8485f94209bf3e01ed169244ab2072ebb0d1c5dc589c95b39a3fbab3641b7a7e","timestamp":1549646257,"pobsindexes":{"BlockHeight":16638,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"144b2b7711fda335cdae5865ab3729d641266087bc4e088d9fba806345045903","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"f09af1c62026aed18d1d8f80e5a7bd4947a6cb5b6b69097c5b10cb983f0d729662c511a4852fa63690884e2b5c600e3935e08b81aaa757d9f0eb740292ec8309"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"5c86c987668ca47948a149413f4f004651249073eff4f144fd26b50e218705a8","difficulty":"30203","estimatedactivebs":"2365","height":16639,"maturitytimestamp":1549646167,"target":[0,2,43,120,39,20,204,42,102,32,125,110,53,77,39,71,99,124,13,223,197,154,115,42,126,62,185,120,208,177,21,190],"totalcoins":"0","arbitrarydatatotalsize":4328,"minerpayoutcount":16721,"transactioncount":17262,"coininputcount":633,"coinoutputcount":1225,"blockstakeinputcount":16639,"blockstakeoutputcount":16640,"minerfeecount":622,"arbitrarydatacount":572},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}') # add the wallet info explorer_client.hash_add('011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f', '{"hashtype":"unlockhash","block":{"minerpayoutids":null,"transactions":null,"rawblock":{"parentid":"0000000000000000000000000000000000000000000000000000000000000000","timestamp":0,"pobsindexes":{"BlockHeight":0,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":null,"transactions":null},"blockid":"0000000000000000000000000000000000000000000000000000000000000000","difficulty":"0","estimatedactivebs":"0","height":0,"maturitytimestamp":0,"target":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"totalcoins":"0","arbitrarydatatotalsize":0,"minerpayoutcount":0,"transactioncount":0,"coininputcount":0,"coinoutputcount":0,"blockstakeinputcount":0,"blockstakeoutputcount":0,"minerfeecount":0,"arbitrarydatacount":0},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":[{"id":"4d64c4f184ef5c7267585df8bc6af8a3e9f5963903c30ff23cfdfb068cccded7","height":16623,"parent":"95caf23ce383e01bd8af5d9391123091426278716ec5eb01a986c833119511df","rawtransaction":{"version":1,"data":{"coininputs":[{"parentid":"c61aebcc2555ea16ef25152966fbbdaf2e7ba6a33c75c1033249cacc6331b2e8","fulfillment":{"type":1,"data":{"publickey":"ed25519:89ba466d80af1b453a435175dbba6da7718e9cb19c64c0ed41fca3e6982e3636","signature":"3f7c30fe4bdfc37a3f483487ef7450ee63fb6d28a7e173d6b372d895f8442ce198bf3b171cfc6315d6f03a37f00675f336a91c25b179f153237330491845f00c"}}}],"coinoutputs":[{"value":"51000000000","condition":{"type":1,"data":{"unlockhash":"011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f"}}},{"value":"999627999999501","condition":{"type":1,"data":{"unlockhash":"0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"}}}],"minerfees":["1000000000"]}},"coininputoutputs":[{"value":"999679999999501","condition":{"type":1,"data":{"unlockhash":"0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"}},"unlockhash":"0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"}],"coinoutputids":["243c1bb1c7dcc18a612cf1cba4ec433f25aaedbd9916b203a66b95635f9e28b2","9516f1c1cafd58e475f424931c2f2ab9d2df62fdd263d0b075b260df80284b47"],"coinoutputunlockhashes":["011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f","0107e83d2bd8a7aad7ab0af0c0a0f1f116fb42335f64eeeb5ed1b76bd63e62ce59a3872a7279ab"],"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false}],"multisigaddresses":null,"unconfirmed":false}') # override internal functionality, as to use our stub client c._explorer_get = explorer_client.explorer_get c._explorer_post = explorer_client.explorer_post # a wallet is required to initiate an atomic swap contract w = c.wallets.new("mytestwallet", seed='survey exile lab cook license sock rose squirrel noodle point they lounge oval kit tape virus loop scare water gorilla baby educate program wish') # money is required to be available in the wallet assert str(w.balance.available) == '51' # an atomic swap contract can be created and signed without being submitted as follows: result = w.atomicswap.initiate( participator='0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6', amount=50, submit=False) # submit=True is the default assert not result.submitted assert result.transaction.is_fulfilled() # the contract is returned as part of the result assert str(result.contract.amount) == '50' assert str(result.contract.sender) == '011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f' assert str(result.contract.receiver) == '0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6' assert result.contract.refund_timestamp > 1549646257 assert result.contract.secret_hash == AtomicSwapSecretHash.from_secret(result.secret) # one would than use `w.transaction_sign(result.transaction)` to submit it for real # However, usually an atomic swap contract is initiated as follows: result = w.atomicswap.initiate( participator='0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6', amount=50, data='the beginning of it all') # data is optional assert result.submitted # the contract is returned as part of the result assert str(result.contract.amount) == '50' assert str(result.contract.sender) == '011dcc29c37e564ef1b0ae6273bddd6fa9c5fe5443f3a18827d3e5733892f37b2439da663e1e6f' assert str(result.contract.receiver) == '0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6' assert result.contract.refund_timestamp > 1549646257 assert result.contract.secret_hash == AtomicSwapSecretHash.from_secret(result.secret) # ensure our contract was submitted transaction = explorer_client.posted_transaction_get(result.transaction.id) contract = AtomicSwapContract(transaction.coin_outputs[0], unspent=True) assert contract == result.contract # and ensure the transaction is fully signed for ci in transaction.coin_inputs: assert len(ci.fulfillment.signature.value) == 64 # FYI: a contract's amount has to be greater than the network's minimum miner fee, # while tfchain does allow it, this client will raise an exception when you # do try to give a value equal to or less than the networks' miner fee. # This because such a contract cannot be redeemed or refunded. with pytest.raises(tfchain.errors.AtomicSwapInsufficientAmountError): w.atomicswap.initiate( participator='0131cb8e9b5214096fd23c8d88795b2887fbc898aa37125a406fc4769a4f9b3c1dc423852868f6', amount=c.minimum_miner_fee-'0.000000001 TFT')
def main(self): """ to run: js_shell 'j.clients.tfchain.test(name="wallet_coins_send")' """ # create a tfchain client for devnet c = j.clients.tfchain.new("mydevclient", network_type="DEV") # or simply `c = j.tfchain.clients.mydevclient`, should the client already exist # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network) explorer_client = TFChainExplorerGetClientStub() # set the current block chain info explorer_client.chain_info = '{"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1}' explorer_client.hash_add( '552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e', '{"hashtype":"blockid","block":{"minerpayoutids":["468db689f752414702ef3a5aa06238f03a4539434a61624b3b8a0fb5dc38a211"],"transactions":[{"id":"2396f8e57bbb9b22bd1d749d5de3fd532ea6886e9660a556a13571d701d83e27","height":3644,"parent":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["f683e7319659c61f54e93546bc41b57c5bffe79de26c06ec7371034465804c81"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"47db4274551b0372564f8d1ab89c596428f00e460c0b416327e53983c8765198","timestamp":1549012665,"pobsindexes":{"BlockHeight":3643,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}' ) # add initial condition explorer_client.mint_condition_add( condition=j.clients.tfchain.types.conditions.from_recipient( '01a006599af1155f43d687635e9680650003a6c506934996b90ae84d07648927414046f9f0e936' ), height=0, ) # overwrite the explorer get/post logic c._explorer_get = explorer_client.explorer_get c._explorer_post = explorer_client.explorer_post # the devnet genesis seed is the seed of the wallet, # which receives all block stakes and coins in the genesis block of the tfchain devnet DEVNET_GENESIS_SEED = "image orchard airport business cost work mountain obscure flee alpha alert salmon damage engage trumpet route marble subway immune short tide young cycle attract" # create a new devnet wallet w = c.wallets.new("mywallet", seed=DEVNET_GENESIS_SEED) # we create a new wallet using an existing seed, # such that our seed is used and not a new randomly generated seed # a tfchain (JS) wallet uses the underlying tfchain client for all its # interaction with the tfchain network assert w.network_type == "DEV" # balance will be fully 0 for wallet due to our stub state assert w.balance.available == 0 assert w.balance.unconfirmed == 0 assert w.balance.locked == 0 # (1) if the wallet has no powers to mint coins, # the transaction will be not be submitted as the transaction won't be fulfilled result = w.minter.coins_new( recipient= '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a', amount=100, ) assert not result.submitted assert not result.transaction.is_fulfilled() assert not result.transaction.mint_fulfillment.is_fulfilled( parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature) # define the current mint condition to be ours explorer_client.mint_condition_add( condition=j.clients.tfchain.types.conditions.from_recipient( '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a' ), height=3643, ) # (2) creating coins and sending it to a personal wallet on the used tfchain network can be done as follows: result = w.minter.coins_new( recipient= "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a", amount="108.24" # the amount of TFT to send ) assert result.submitted # it is expected the transaction is submitted # validate more for testing purposes assert result.transaction.is_fulfilled() assert result.transaction.mint_fulfillment.is_fulfilled( parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature) assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a' # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == result.transaction.json() # (3) creating coins and sending it to a personal wallet with a lock and data is possible as well result = w.minter.coins_new( recipient= "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f", amount=200, # the amount of TFT to send lock= '07/12/2020 14:35', # a lock can be a timestamp, data-time str, duration str, or block height data='maximum 83 bytes can be used as optional data') assert result.submitted # it is expected the transaction is submitted # validate more for testing purposes assert result.transaction.is_fulfilled() assert result.transaction.mint_fulfillment.is_fulfilled( parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature) assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a' # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == result.transaction.json() # (4) one can also send to a full multi-sig wallet, when creating coins result = w.minter.coins_new( recipient=[ "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f", "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a" ], amount="50 TFT", # the amount of TFT to send lock= 1550665225, # a lock can be a timestamp, data-time str, duration str, or block height data=b'binary data can be added as well') assert result.submitted # it is expected the transaction is submitted # validate more for testing purposes assert result.transaction.is_fulfilled() assert result.transaction.mint_fulfillment.is_fulfilled( parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature) assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a' # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == result.transaction.json() # (5) one can also send to a x-out-of-n multisig wallet, when creating coins result = w.minter.coins_new( recipient=(1, [ "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f", "014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a" ]), amount='300.0', # the amount of TFT to send lock= 35000, # a lock can be a timestamp, data-time str, duration str, or block height data=bytearray(b'binary data can be added as well')) assert result.submitted # it is expected the transaction is submitted # validate more for testing purposes assert result.transaction.is_fulfilled() assert result.transaction.mint_fulfillment.is_fulfilled( parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature) assert result.transaction.parent_mint_condition.unlockhash == '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a' # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == result.transaction.json() # define the minter condition as multi-sig explorer_client.mint_condition_add( condition=j.clients.tfchain.types.conditions.from_recipient((1, [ '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a', '011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f', ])), height=3643, force=True) # (6) creating coins and sending works the same if the condition is multi-sig, # the only difference is that it might be possible that the transaction is not submitted yet, # should more signatures be required in order to fulfill the mint fulfillment result = w.minter.coins_new( recipient= "015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f", amount="108.24" # the amount of TFT to send ) assert result.submitted # it is expected the transaction is submitted # validate more for testing purposes assert result.transaction.is_fulfilled() assert result.transaction.mint_fulfillment.is_fulfilled( parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentMultiSignature) assert result.transaction.parent_mint_condition.unlockhash == '039481e77f55a2a4aee707c07d69a11b1d9dc4100ccc50b9f82d56b411826014e5ea1f477be065' # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == result.transaction.json()
def main(self): """ to run: js_shell 'j.clients.tfchain.test(name="minter_condition_set")' """ # create a tfchain client for devnet c = j.clients.tfchain.new("mydevclient", network_type="DEV") # or simply `c = j.tfchain.clients.mydevclient`, should the client already exist # (we replace internal client logic with custom logic as to ensure we can test without requiring an active network) explorer_client = TFChainExplorerGetClientStub() # define current block height explorer_client.chain_info = '{"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1}' explorer_client.hash_add('552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e', '{"hashtype":"blockid","block":{"minerpayoutids":["468db689f752414702ef3a5aa06238f03a4539434a61624b3b8a0fb5dc38a211"],"transactions":[{"id":"2396f8e57bbb9b22bd1d749d5de3fd532ea6886e9660a556a13571d701d83e27","height":3644,"parent":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","rawtransaction":{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}},"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"blockstakeoutputids":["f683e7319659c61f54e93546bc41b57c5bffe79de26c06ec7371034465804c81"],"blockstakeunlockhashes":["015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"],"unconfirmed":false}],"rawblock":{"parentid":"47db4274551b0372564f8d1ab89c596428f00e460c0b416327e53983c8765198","timestamp":1549012665,"pobsindexes":{"BlockHeight":3643,"TransactionIndex":0,"OutputIndex":0},"minerpayouts":[{"value":"10000000000","unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}],"transactions":[{"version":1,"data":{"coininputs":null,"blockstakeinputs":[{"parentid":"ff5a002ec356b7cb24fbee9f076f239fb8c72d5a8a448cee92ee6d29a87aef52","fulfillment":{"type":1,"data":{"publickey":"ed25519:d285f92d6d449d9abb27f4c6cf82713cec0696d62b8c123f1627e054dc6d7780","signature":"7bec94dfb87640726c6a14de2110599db0f81cf9fa456249e7bf79b0c74b79517edde25c4ee87f181880af44fe6ee054ff20b74eda2144fe07fa5bfb9d884208"}}}],"blockstakeoutputs":[{"value":"3000","condition":{"type":1,"data":{"unlockhash":"015a080a9259b9d4aaa550e2156f49b1a79a64c7ea463d810d4493e8242e6791584fbdac553e6f"}}}],"minerfees":null}}]},"blockid":"552e410481cce1358ffcd4687f4199dd2181c799d55da26178e55643355bbd2e","difficulty":"27801","estimatedactivebs":"59","height":3644,"maturitytimestamp":1549012510,"target":[0,2,91,116,78,165,130,72,116,162,127,4,125,67,108,16,140,247,132,198,107,159,114,177,44,25,18,162,38,157,169,245],"totalcoins":"0","arbitrarydatatotalsize":6,"minerpayoutcount":3650,"transactioncount":3652,"coininputcount":12,"coinoutputcount":15,"blockstakeinputcount":3644,"blockstakeoutputcount":3645,"minerfeecount":7,"arbitrarydatacount":1},"blocks":null,"transaction":{"id":"0000000000000000000000000000000000000000000000000000000000000000","height":0,"parent":"0000000000000000000000000000000000000000000000000000000000000000","rawtransaction":{"version":0,"data":{"coininputs":[],"minerfees":null}},"coininputoutputs":null,"coinoutputids":null,"coinoutputunlockhashes":null,"blockstakeinputoutputs":null,"blockstakeoutputids":null,"blockstakeunlockhashes":null,"unconfirmed":false},"transactions":null,"multisigaddresses":null,"unconfirmed":false}') # add initial condition explorer_client.mint_condition_add( condition=conditions.from_recipient('01a006599af1155f43d687635e9680650003a6c506934996b90ae84d07648927414046f9f0e936'), height=0, ) # overwrite get/post logic c._explorer_get = explorer_client.explorer_get c._explorer_post = explorer_client.explorer_post # the devnet genesis seed is the seed of the wallet, # which receives all block stakes and coins in the genesis block of the tfchain devnet DEVNET_GENESIS_SEED="image orchard airport business cost work mountain obscure flee alpha alert salmon damage engage trumpet route marble subway immune short tide young cycle attract" # create a new devnet wallet w = c.wallets.new("mywallet", seed=DEVNET_GENESIS_SEED) # we create a new wallet using an existing seed, # such that our seed is used and not a new randomly generated seed # only if you have the correct minting powers, # you can set a new minter definition, otherwise an error will be raised # set another mint condition manually explorer_client.mint_condition_add( condition=conditions.from_recipient('014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a'), height=3643, ) condition = c.minter.condition_get() assert condition.unlockhash == w.address # (1) once you have the correct powers, you can can overwrite it as follows: result = w.minter.definition_set(minter=(1, [ '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a', '011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f', ])) # check if the current transaction is submitted assert result.submitted # it is expected # check if all is fulfilled assert result.transaction.is_fulfilled() assert result.transaction.mint_fulfillment.is_fulfilled(parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature) # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == result.transaction.json() # set another mint condition manually explorer_client.mint_condition_add( condition=conditions.from_recipient((1, [ '014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a', '011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f', ])), height=3644, ) # (2) when defining a new minter definition you can also attach data if desired result = w.minter.definition_set( minter='011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f', # new minter power data='redefine minter conditions', # optional data, can also be as binary data ) assert result.submitted # it is expected the transaction is submitted assert result.transaction.is_fulfilled() assert result.transaction.mint_fulfillment.is_fulfilled(parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentMultiSignature) # ensure the transaction is posted and as expected there as well txn = explorer_client.posted_transaction_get(result.transaction.id) assert txn.json() == result.transaction.json() # set another mint condition manually explorer_client.mint_condition_add( condition=conditions.from_recipient('011cf61451b58970eeead00819e33f7fc812bd9b2d4e66914efa6163e238752d34be252ac8667f'), height=3645, ) # if an invalid recipient is given it, a ValueError or TypeError is raised with pytest.raises(ValueError): w.minter.definition_set(minter=None) with pytest.raises(ValueError): w.minter.definition_set(minter='0123bla') with pytest.raises(TypeError): w.minter.definition_set(minter=1) # (3) if the wallet has no powers to redefine the powers, # the transaction will be not be submitted as the transaction won't be fulfilled result = w.minter.definition_set(minter='014ad318772a09de75fb62f084a33188a7f6fb5e7b68c0ed85a5f90fe11246386b7e6fe97a5a6a') assert not result.submitted assert not result.transaction.is_fulfilled() assert not result.transaction.mint_fulfillment.is_fulfilled(parent_condition=c.minter.condition_get()) assert isinstance(result.transaction.mint_fulfillment, FulfillmentSingleSignature)