chia-blockchain 2.5.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1042) hide show
  1. chia/__init__.py +10 -0
  2. chia/__main__.py +5 -0
  3. chia/_tests/README.md +53 -0
  4. chia/_tests/__init__.py +0 -0
  5. chia/_tests/blockchain/__init__.py +0 -0
  6. chia/_tests/blockchain/blockchain_test_utils.py +195 -0
  7. chia/_tests/blockchain/config.py +4 -0
  8. chia/_tests/blockchain/test_augmented_chain.py +145 -0
  9. chia/_tests/blockchain/test_blockchain.py +4202 -0
  10. chia/_tests/blockchain/test_blockchain_transactions.py +1031 -0
  11. chia/_tests/blockchain/test_build_chains.py +59 -0
  12. chia/_tests/blockchain/test_get_block_generator.py +72 -0
  13. chia/_tests/blockchain/test_lookup_fork_chain.py +194 -0
  14. chia/_tests/build-init-files.py +92 -0
  15. chia/_tests/build-job-matrix.py +204 -0
  16. chia/_tests/check_pytest_monitor_output.py +34 -0
  17. chia/_tests/check_sql_statements.py +72 -0
  18. chia/_tests/chia-start-sim +42 -0
  19. chia/_tests/clvm/__init__.py +0 -0
  20. chia/_tests/clvm/benchmark_costs.py +23 -0
  21. chia/_tests/clvm/coin_store.py +149 -0
  22. chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
  23. chia/_tests/clvm/test_clvm_step.py +37 -0
  24. chia/_tests/clvm/test_condition_codes.py +13 -0
  25. chia/_tests/clvm/test_curry_and_treehash.py +55 -0
  26. chia/_tests/clvm/test_message_conditions.py +184 -0
  27. chia/_tests/clvm/test_program.py +150 -0
  28. chia/_tests/clvm/test_puzzle_compression.py +143 -0
  29. chia/_tests/clvm/test_puzzle_drivers.py +45 -0
  30. chia/_tests/clvm/test_puzzles.py +242 -0
  31. chia/_tests/clvm/test_singletons.py +540 -0
  32. chia/_tests/clvm/test_spend_sim.py +181 -0
  33. chia/_tests/cmds/__init__.py +0 -0
  34. chia/_tests/cmds/cmd_test_utils.py +469 -0
  35. chia/_tests/cmds/config.py +3 -0
  36. chia/_tests/cmds/conftest.py +23 -0
  37. chia/_tests/cmds/test_click_types.py +200 -0
  38. chia/_tests/cmds/test_cmd_framework.py +620 -0
  39. chia/_tests/cmds/test_cmds_util.py +97 -0
  40. chia/_tests/cmds/test_daemon.py +92 -0
  41. chia/_tests/cmds/test_dev_gh.py +131 -0
  42. chia/_tests/cmds/test_farm_cmd.py +66 -0
  43. chia/_tests/cmds/test_show.py +116 -0
  44. chia/_tests/cmds/test_sim.py +207 -0
  45. chia/_tests/cmds/test_timelock_args.py +75 -0
  46. chia/_tests/cmds/test_tx_config_args.py +154 -0
  47. chia/_tests/cmds/testing_classes.py +59 -0
  48. chia/_tests/cmds/wallet/__init__.py +0 -0
  49. chia/_tests/cmds/wallet/test_consts.py +47 -0
  50. chia/_tests/cmds/wallet/test_dao.py +565 -0
  51. chia/_tests/cmds/wallet/test_did.py +403 -0
  52. chia/_tests/cmds/wallet/test_nft.py +471 -0
  53. chia/_tests/cmds/wallet/test_notifications.py +124 -0
  54. chia/_tests/cmds/wallet/test_offer.toffer +1 -0
  55. chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
  56. chia/_tests/cmds/wallet/test_vcs.py +400 -0
  57. chia/_tests/cmds/wallet/test_wallet.py +1125 -0
  58. chia/_tests/cmds/wallet/test_wallet_check.py +109 -0
  59. chia/_tests/conftest.py +1419 -0
  60. chia/_tests/connection_utils.py +125 -0
  61. chia/_tests/core/__init__.py +0 -0
  62. chia/_tests/core/cmds/__init__.py +0 -0
  63. chia/_tests/core/cmds/test_beta.py +382 -0
  64. chia/_tests/core/cmds/test_keys.py +1734 -0
  65. chia/_tests/core/cmds/test_wallet.py +126 -0
  66. chia/_tests/core/config.py +3 -0
  67. chia/_tests/core/consensus/__init__.py +0 -0
  68. chia/_tests/core/consensus/test_block_creation.py +54 -0
  69. chia/_tests/core/consensus/test_pot_iterations.py +117 -0
  70. chia/_tests/core/custom_types/__init__.py +0 -0
  71. chia/_tests/core/custom_types/test_coin.py +107 -0
  72. chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
  73. chia/_tests/core/custom_types/test_spend_bundle.py +70 -0
  74. chia/_tests/core/daemon/__init__.py +0 -0
  75. chia/_tests/core/daemon/config.py +4 -0
  76. chia/_tests/core/daemon/test_daemon.py +2128 -0
  77. chia/_tests/core/daemon/test_daemon_register.py +109 -0
  78. chia/_tests/core/daemon/test_keychain_proxy.py +101 -0
  79. chia/_tests/core/data_layer/__init__.py +0 -0
  80. chia/_tests/core/data_layer/config.py +5 -0
  81. chia/_tests/core/data_layer/conftest.py +106 -0
  82. chia/_tests/core/data_layer/test_data_cli.py +56 -0
  83. chia/_tests/core/data_layer/test_data_layer.py +83 -0
  84. chia/_tests/core/data_layer/test_data_layer_util.py +218 -0
  85. chia/_tests/core/data_layer/test_data_rpc.py +3847 -0
  86. chia/_tests/core/data_layer/test_data_store.py +2424 -0
  87. chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
  88. chia/_tests/core/data_layer/test_plugin.py +91 -0
  89. chia/_tests/core/data_layer/util.py +233 -0
  90. chia/_tests/core/farmer/__init__.py +0 -0
  91. chia/_tests/core/farmer/config.py +3 -0
  92. chia/_tests/core/farmer/test_farmer_api.py +103 -0
  93. chia/_tests/core/full_node/__init__.py +0 -0
  94. chia/_tests/core/full_node/config.py +4 -0
  95. chia/_tests/core/full_node/dos/__init__.py +0 -0
  96. chia/_tests/core/full_node/dos/config.py +3 -0
  97. chia/_tests/core/full_node/full_sync/__init__.py +0 -0
  98. chia/_tests/core/full_node/full_sync/config.py +4 -0
  99. chia/_tests/core/full_node/full_sync/test_full_sync.py +443 -0
  100. chia/_tests/core/full_node/ram_db.py +27 -0
  101. chia/_tests/core/full_node/stores/__init__.py +0 -0
  102. chia/_tests/core/full_node/stores/config.py +4 -0
  103. chia/_tests/core/full_node/stores/test_block_store.py +590 -0
  104. chia/_tests/core/full_node/stores/test_coin_store.py +897 -0
  105. chia/_tests/core/full_node/stores/test_full_node_store.py +1219 -0
  106. chia/_tests/core/full_node/stores/test_hint_store.py +229 -0
  107. chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
  108. chia/_tests/core/full_node/test_address_manager.py +588 -0
  109. chia/_tests/core/full_node/test_block_height_map.py +556 -0
  110. chia/_tests/core/full_node/test_conditions.py +556 -0
  111. chia/_tests/core/full_node/test_full_node.py +2700 -0
  112. chia/_tests/core/full_node/test_generator_tools.py +82 -0
  113. chia/_tests/core/full_node/test_hint_management.py +104 -0
  114. chia/_tests/core/full_node/test_node_load.py +34 -0
  115. chia/_tests/core/full_node/test_performance.py +179 -0
  116. chia/_tests/core/full_node/test_subscriptions.py +492 -0
  117. chia/_tests/core/full_node/test_transactions.py +203 -0
  118. chia/_tests/core/full_node/test_tx_processing_queue.py +155 -0
  119. chia/_tests/core/large_block.py +2388 -0
  120. chia/_tests/core/make_block_generator.py +70 -0
  121. chia/_tests/core/mempool/__init__.py +0 -0
  122. chia/_tests/core/mempool/config.py +4 -0
  123. chia/_tests/core/mempool/test_mempool.py +3255 -0
  124. chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
  125. chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
  126. chia/_tests/core/mempool/test_mempool_item_queries.py +190 -0
  127. chia/_tests/core/mempool/test_mempool_manager.py +2084 -0
  128. chia/_tests/core/mempool/test_mempool_performance.py +64 -0
  129. chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
  130. chia/_tests/core/node_height.py +28 -0
  131. chia/_tests/core/server/__init__.py +0 -0
  132. chia/_tests/core/server/config.py +3 -0
  133. chia/_tests/core/server/flood.py +84 -0
  134. chia/_tests/core/server/serve.py +135 -0
  135. chia/_tests/core/server/test_api_protocol.py +21 -0
  136. chia/_tests/core/server/test_capabilities.py +66 -0
  137. chia/_tests/core/server/test_dos.py +319 -0
  138. chia/_tests/core/server/test_event_loop.py +109 -0
  139. chia/_tests/core/server/test_loop.py +294 -0
  140. chia/_tests/core/server/test_node_discovery.py +73 -0
  141. chia/_tests/core/server/test_rate_limits.py +482 -0
  142. chia/_tests/core/server/test_server.py +226 -0
  143. chia/_tests/core/server/test_upnp.py +8 -0
  144. chia/_tests/core/services/__init__.py +0 -0
  145. chia/_tests/core/services/config.py +3 -0
  146. chia/_tests/core/services/test_services.py +188 -0
  147. chia/_tests/core/ssl/__init__.py +0 -0
  148. chia/_tests/core/ssl/config.py +3 -0
  149. chia/_tests/core/ssl/test_ssl.py +202 -0
  150. chia/_tests/core/test_coins.py +33 -0
  151. chia/_tests/core/test_cost_calculation.py +313 -0
  152. chia/_tests/core/test_crawler.py +175 -0
  153. chia/_tests/core/test_crawler_rpc.py +53 -0
  154. chia/_tests/core/test_daemon_rpc.py +24 -0
  155. chia/_tests/core/test_db_conversion.py +130 -0
  156. chia/_tests/core/test_db_validation.py +162 -0
  157. chia/_tests/core/test_farmer_harvester_rpc.py +505 -0
  158. chia/_tests/core/test_filter.py +35 -0
  159. chia/_tests/core/test_full_node_rpc.py +768 -0
  160. chia/_tests/core/test_merkle_set.py +343 -0
  161. chia/_tests/core/test_program.py +47 -0
  162. chia/_tests/core/test_rpc_util.py +86 -0
  163. chia/_tests/core/test_seeder.py +420 -0
  164. chia/_tests/core/test_setproctitle.py +13 -0
  165. chia/_tests/core/util/__init__.py +0 -0
  166. chia/_tests/core/util/config.py +4 -0
  167. chia/_tests/core/util/test_block_cache.py +44 -0
  168. chia/_tests/core/util/test_cached_bls.py +57 -0
  169. chia/_tests/core/util/test_config.py +337 -0
  170. chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
  171. chia/_tests/core/util/test_files.py +391 -0
  172. chia/_tests/core/util/test_jsonify.py +146 -0
  173. chia/_tests/core/util/test_keychain.py +522 -0
  174. chia/_tests/core/util/test_keyring_wrapper.py +491 -0
  175. chia/_tests/core/util/test_lockfile.py +380 -0
  176. chia/_tests/core/util/test_log_exceptions.py +187 -0
  177. chia/_tests/core/util/test_lru_cache.py +56 -0
  178. chia/_tests/core/util/test_significant_bits.py +40 -0
  179. chia/_tests/core/util/test_streamable.py +883 -0
  180. chia/_tests/db/__init__.py +0 -0
  181. chia/_tests/db/test_db_wrapper.py +566 -0
  182. chia/_tests/environments/__init__.py +0 -0
  183. chia/_tests/environments/common.py +35 -0
  184. chia/_tests/environments/full_node.py +47 -0
  185. chia/_tests/environments/wallet.py +429 -0
  186. chia/_tests/ether.py +19 -0
  187. chia/_tests/farmer_harvester/__init__.py +0 -0
  188. chia/_tests/farmer_harvester/config.py +3 -0
  189. chia/_tests/farmer_harvester/test_farmer.py +1264 -0
  190. chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
  191. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +131 -0
  192. chia/_tests/farmer_harvester/test_third_party_harvesters.py +528 -0
  193. chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
  194. chia/_tests/fee_estimation/__init__.py +0 -0
  195. chia/_tests/fee_estimation/config.py +3 -0
  196. chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
  197. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
  198. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +144 -0
  199. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
  200. chia/_tests/generator/__init__.py +0 -0
  201. chia/_tests/generator/puzzles/__init__.py +0 -0
  202. chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
  203. chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
  204. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
  205. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
  206. chia/_tests/generator/test_compression.py +201 -0
  207. chia/_tests/generator/test_generator_types.py +44 -0
  208. chia/_tests/generator/test_rom.py +180 -0
  209. chia/_tests/plot_sync/__init__.py +0 -0
  210. chia/_tests/plot_sync/config.py +3 -0
  211. chia/_tests/plot_sync/test_delta.py +101 -0
  212. chia/_tests/plot_sync/test_plot_sync.py +618 -0
  213. chia/_tests/plot_sync/test_receiver.py +451 -0
  214. chia/_tests/plot_sync/test_sender.py +116 -0
  215. chia/_tests/plot_sync/test_sync_simulated.py +451 -0
  216. chia/_tests/plot_sync/util.py +68 -0
  217. chia/_tests/plotting/__init__.py +0 -0
  218. chia/_tests/plotting/config.py +3 -0
  219. chia/_tests/plotting/test_plot_manager.py +781 -0
  220. chia/_tests/plotting/util.py +12 -0
  221. chia/_tests/pools/__init__.py +0 -0
  222. chia/_tests/pools/config.py +5 -0
  223. chia/_tests/pools/test_pool_cli_parsing.py +128 -0
  224. chia/_tests/pools/test_pool_cmdline.py +1001 -0
  225. chia/_tests/pools/test_pool_config.py +42 -0
  226. chia/_tests/pools/test_pool_puzzles_lifecycle.py +397 -0
  227. chia/_tests/pools/test_pool_rpc.py +1123 -0
  228. chia/_tests/pools/test_pool_wallet.py +205 -0
  229. chia/_tests/pools/test_wallet_pool_store.py +161 -0
  230. chia/_tests/process_junit.py +348 -0
  231. chia/_tests/rpc/__init__.py +0 -0
  232. chia/_tests/rpc/test_rpc_client.py +138 -0
  233. chia/_tests/rpc/test_rpc_server.py +183 -0
  234. chia/_tests/simulation/__init__.py +0 -0
  235. chia/_tests/simulation/config.py +6 -0
  236. chia/_tests/simulation/test_simulation.py +501 -0
  237. chia/_tests/simulation/test_simulator.py +232 -0
  238. chia/_tests/simulation/test_start_simulator.py +107 -0
  239. chia/_tests/testconfig.py +13 -0
  240. chia/_tests/timelord/__init__.py +0 -0
  241. chia/_tests/timelord/config.py +3 -0
  242. chia/_tests/timelord/test_new_peak.py +437 -0
  243. chia/_tests/timelord/test_timelord.py +11 -0
  244. chia/_tests/tools/1315537.json +170 -0
  245. chia/_tests/tools/1315544.json +160 -0
  246. chia/_tests/tools/1315630.json +150 -0
  247. chia/_tests/tools/300000.json +105 -0
  248. chia/_tests/tools/442734.json +140 -0
  249. chia/_tests/tools/466212.json +130 -0
  250. chia/_tests/tools/__init__.py +0 -0
  251. chia/_tests/tools/config.py +5 -0
  252. chia/_tests/tools/test-blockchain-db.sqlite +0 -0
  253. chia/_tests/tools/test_full_sync.py +30 -0
  254. chia/_tests/tools/test_legacy_keyring.py +82 -0
  255. chia/_tests/tools/test_run_block.py +128 -0
  256. chia/_tests/tools/test_virtual_project.py +591 -0
  257. chia/_tests/util/__init__.py +0 -0
  258. chia/_tests/util/benchmark_cost.py +170 -0
  259. chia/_tests/util/benchmarks.py +153 -0
  260. chia/_tests/util/bip39_test_vectors.json +148 -0
  261. chia/_tests/util/blockchain.py +134 -0
  262. chia/_tests/util/blockchain_mock.py +132 -0
  263. chia/_tests/util/build_network_protocol_files.py +302 -0
  264. chia/_tests/util/clvm_generator.bin +0 -0
  265. chia/_tests/util/config.py +3 -0
  266. chia/_tests/util/constants.py +20 -0
  267. chia/_tests/util/db_connection.py +37 -0
  268. chia/_tests/util/full_sync.py +253 -0
  269. chia/_tests/util/gen_ssl_certs.py +114 -0
  270. chia/_tests/util/generator_tools_testing.py +45 -0
  271. chia/_tests/util/get_name_puzzle_conditions.py +52 -0
  272. chia/_tests/util/key_tool.py +36 -0
  273. chia/_tests/util/misc.py +675 -0
  274. chia/_tests/util/network_protocol_data.py +1072 -0
  275. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  276. chia/_tests/util/protocol_messages_json.py +2701 -0
  277. chia/_tests/util/rpc.py +26 -0
  278. chia/_tests/util/run_block.py +163 -0
  279. chia/_tests/util/setup_nodes.py +481 -0
  280. chia/_tests/util/spend_sim.py +492 -0
  281. chia/_tests/util/split_managers.py +102 -0
  282. chia/_tests/util/temp_file.py +14 -0
  283. chia/_tests/util/test_action_scope.py +144 -0
  284. chia/_tests/util/test_async_pool.py +366 -0
  285. chia/_tests/util/test_build_job_matrix.py +42 -0
  286. chia/_tests/util/test_build_network_protocol_files.py +7 -0
  287. chia/_tests/util/test_chia_version.py +50 -0
  288. chia/_tests/util/test_collection.py +11 -0
  289. chia/_tests/util/test_condition_tools.py +229 -0
  290. chia/_tests/util/test_config.py +426 -0
  291. chia/_tests/util/test_dump_keyring.py +60 -0
  292. chia/_tests/util/test_errors.py +10 -0
  293. chia/_tests/util/test_full_block_utils.py +279 -0
  294. chia/_tests/util/test_installed.py +20 -0
  295. chia/_tests/util/test_limited_semaphore.py +53 -0
  296. chia/_tests/util/test_logging_filter.py +42 -0
  297. chia/_tests/util/test_misc.py +445 -0
  298. chia/_tests/util/test_network.py +73 -0
  299. chia/_tests/util/test_network_protocol_files.py +578 -0
  300. chia/_tests/util/test_network_protocol_json.py +267 -0
  301. chia/_tests/util/test_network_protocol_test.py +256 -0
  302. chia/_tests/util/test_paginator.py +71 -0
  303. chia/_tests/util/test_pprint.py +17 -0
  304. chia/_tests/util/test_priority_mutex.py +488 -0
  305. chia/_tests/util/test_recursive_replace.py +116 -0
  306. chia/_tests/util/test_replace_str_to_bytes.py +137 -0
  307. chia/_tests/util/test_service_groups.py +15 -0
  308. chia/_tests/util/test_ssl_check.py +31 -0
  309. chia/_tests/util/test_testnet_overrides.py +19 -0
  310. chia/_tests/util/test_tests_misc.py +38 -0
  311. chia/_tests/util/test_timing.py +37 -0
  312. chia/_tests/util/test_trusted_peer.py +51 -0
  313. chia/_tests/util/time_out_assert.py +191 -0
  314. chia/_tests/wallet/__init__.py +0 -0
  315. chia/_tests/wallet/cat_wallet/__init__.py +0 -0
  316. chia/_tests/wallet/cat_wallet/config.py +4 -0
  317. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
  318. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
  319. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1826 -0
  320. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
  321. chia/_tests/wallet/cat_wallet/test_trades.py +2600 -0
  322. chia/_tests/wallet/clawback/__init__.py +0 -0
  323. chia/_tests/wallet/clawback/config.py +3 -0
  324. chia/_tests/wallet/clawback/test_clawback_decorator.py +78 -0
  325. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
  326. chia/_tests/wallet/clawback/test_clawback_metadata.py +50 -0
  327. chia/_tests/wallet/config.py +4 -0
  328. chia/_tests/wallet/conftest.py +278 -0
  329. chia/_tests/wallet/dao_wallet/__init__.py +0 -0
  330. chia/_tests/wallet/dao_wallet/config.py +3 -0
  331. chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1330 -0
  332. chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
  333. chia/_tests/wallet/db_wallet/__init__.py +0 -0
  334. chia/_tests/wallet/db_wallet/config.py +3 -0
  335. chia/_tests/wallet/db_wallet/test_db_graftroot.py +141 -0
  336. chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
  337. chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
  338. chia/_tests/wallet/did_wallet/__init__.py +0 -0
  339. chia/_tests/wallet/did_wallet/config.py +4 -0
  340. chia/_tests/wallet/did_wallet/test_did.py +2284 -0
  341. chia/_tests/wallet/nft_wallet/__init__.py +0 -0
  342. chia/_tests/wallet/nft_wallet/config.py +4 -0
  343. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1493 -0
  344. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1024 -0
  345. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +375 -0
  346. chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
  347. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
  348. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2584 -0
  349. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
  350. chia/_tests/wallet/rpc/__init__.py +0 -0
  351. chia/_tests/wallet/rpc/config.py +4 -0
  352. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +285 -0
  353. chia/_tests/wallet/rpc/test_wallet_rpc.py +3153 -0
  354. chia/_tests/wallet/simple_sync/__init__.py +0 -0
  355. chia/_tests/wallet/simple_sync/config.py +3 -0
  356. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +718 -0
  357. chia/_tests/wallet/sync/__init__.py +0 -0
  358. chia/_tests/wallet/sync/config.py +4 -0
  359. chia/_tests/wallet/sync/test_wallet_sync.py +1692 -0
  360. chia/_tests/wallet/test_address_type.py +189 -0
  361. chia/_tests/wallet/test_bech32m.py +45 -0
  362. chia/_tests/wallet/test_clvm_streamable.py +244 -0
  363. chia/_tests/wallet/test_coin_management.py +354 -0
  364. chia/_tests/wallet/test_coin_selection.py +588 -0
  365. chia/_tests/wallet/test_conditions.py +400 -0
  366. chia/_tests/wallet/test_debug_spend_bundle.py +218 -0
  367. chia/_tests/wallet/test_new_wallet_protocol.py +1174 -0
  368. chia/_tests/wallet/test_nft_store.py +192 -0
  369. chia/_tests/wallet/test_notifications.py +196 -0
  370. chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
  371. chia/_tests/wallet/test_puzzle_store.py +132 -0
  372. chia/_tests/wallet/test_sign_coin_spends.py +159 -0
  373. chia/_tests/wallet/test_signer_protocol.py +947 -0
  374. chia/_tests/wallet/test_singleton.py +122 -0
  375. chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
  376. chia/_tests/wallet/test_singleton_store.py +152 -0
  377. chia/_tests/wallet/test_taproot.py +19 -0
  378. chia/_tests/wallet/test_transaction_store.py +945 -0
  379. chia/_tests/wallet/test_util.py +185 -0
  380. chia/_tests/wallet/test_wallet.py +2139 -0
  381. chia/_tests/wallet/test_wallet_action_scope.py +85 -0
  382. chia/_tests/wallet/test_wallet_blockchain.py +111 -0
  383. chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
  384. chia/_tests/wallet/test_wallet_interested_store.py +43 -0
  385. chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
  386. chia/_tests/wallet/test_wallet_node.py +780 -0
  387. chia/_tests/wallet/test_wallet_retry.py +95 -0
  388. chia/_tests/wallet/test_wallet_state_manager.py +259 -0
  389. chia/_tests/wallet/test_wallet_test_framework.py +275 -0
  390. chia/_tests/wallet/test_wallet_trade_store.py +218 -0
  391. chia/_tests/wallet/test_wallet_user_store.py +34 -0
  392. chia/_tests/wallet/test_wallet_utils.py +156 -0
  393. chia/_tests/wallet/vc_wallet/__init__.py +0 -0
  394. chia/_tests/wallet/vc_wallet/config.py +3 -0
  395. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
  396. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
  397. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +830 -0
  398. chia/_tests/wallet/wallet_block_tools.py +327 -0
  399. chia/_tests/weight_proof/__init__.py +0 -0
  400. chia/_tests/weight_proof/config.py +3 -0
  401. chia/_tests/weight_proof/test_weight_proof.py +528 -0
  402. chia/apis.py +19 -0
  403. chia/clvm/__init__.py +0 -0
  404. chia/cmds/__init__.py +0 -0
  405. chia/cmds/beta.py +184 -0
  406. chia/cmds/beta_funcs.py +137 -0
  407. chia/cmds/check_wallet_db.py +420 -0
  408. chia/cmds/chia.py +151 -0
  409. chia/cmds/cmd_classes.py +323 -0
  410. chia/cmds/cmd_helpers.py +242 -0
  411. chia/cmds/cmds_util.py +488 -0
  412. chia/cmds/coin_funcs.py +275 -0
  413. chia/cmds/coins.py +182 -0
  414. chia/cmds/completion.py +49 -0
  415. chia/cmds/configure.py +332 -0
  416. chia/cmds/dao.py +1064 -0
  417. chia/cmds/dao_funcs.py +598 -0
  418. chia/cmds/data.py +708 -0
  419. chia/cmds/data_funcs.py +385 -0
  420. chia/cmds/db.py +87 -0
  421. chia/cmds/db_backup_func.py +77 -0
  422. chia/cmds/db_upgrade_func.py +452 -0
  423. chia/cmds/db_validate_func.py +184 -0
  424. chia/cmds/dev.py +18 -0
  425. chia/cmds/farm.py +100 -0
  426. chia/cmds/farm_funcs.py +200 -0
  427. chia/cmds/gh.py +275 -0
  428. chia/cmds/init.py +63 -0
  429. chia/cmds/init_funcs.py +367 -0
  430. chia/cmds/installers.py +131 -0
  431. chia/cmds/keys.py +527 -0
  432. chia/cmds/keys_funcs.py +863 -0
  433. chia/cmds/netspace.py +50 -0
  434. chia/cmds/netspace_funcs.py +54 -0
  435. chia/cmds/options.py +32 -0
  436. chia/cmds/param_types.py +238 -0
  437. chia/cmds/passphrase.py +131 -0
  438. chia/cmds/passphrase_funcs.py +292 -0
  439. chia/cmds/peer.py +51 -0
  440. chia/cmds/peer_funcs.py +129 -0
  441. chia/cmds/plotnft.py +260 -0
  442. chia/cmds/plotnft_funcs.py +405 -0
  443. chia/cmds/plots.py +230 -0
  444. chia/cmds/plotters.py +18 -0
  445. chia/cmds/rpc.py +208 -0
  446. chia/cmds/show.py +72 -0
  447. chia/cmds/show_funcs.py +215 -0
  448. chia/cmds/signer.py +296 -0
  449. chia/cmds/sim.py +225 -0
  450. chia/cmds/sim_funcs.py +509 -0
  451. chia/cmds/start.py +24 -0
  452. chia/cmds/start_funcs.py +109 -0
  453. chia/cmds/stop.py +62 -0
  454. chia/cmds/units.py +9 -0
  455. chia/cmds/wallet.py +1901 -0
  456. chia/cmds/wallet_funcs.py +1874 -0
  457. chia/consensus/__init__.py +0 -0
  458. chia/consensus/block_body_validation.py +562 -0
  459. chia/consensus/block_creation.py +546 -0
  460. chia/consensus/block_header_validation.py +1059 -0
  461. chia/consensus/block_record.py +31 -0
  462. chia/consensus/block_rewards.py +53 -0
  463. chia/consensus/blockchain.py +1087 -0
  464. chia/consensus/blockchain_interface.py +56 -0
  465. chia/consensus/coinbase.py +30 -0
  466. chia/consensus/condition_costs.py +9 -0
  467. chia/consensus/constants.py +49 -0
  468. chia/consensus/cost_calculator.py +15 -0
  469. chia/consensus/default_constants.py +89 -0
  470. chia/consensus/deficit.py +55 -0
  471. chia/consensus/difficulty_adjustment.py +412 -0
  472. chia/consensus/find_fork_point.py +111 -0
  473. chia/consensus/full_block_to_block_record.py +167 -0
  474. chia/consensus/get_block_challenge.py +106 -0
  475. chia/consensus/get_block_generator.py +27 -0
  476. chia/consensus/make_sub_epoch_summary.py +210 -0
  477. chia/consensus/multiprocess_validation.py +268 -0
  478. chia/consensus/pos_quality.py +19 -0
  479. chia/consensus/pot_iterations.py +67 -0
  480. chia/consensus/puzzles/__init__.py +0 -0
  481. chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
  482. chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
  483. chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
  484. chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
  485. chia/consensus/vdf_info_computation.py +156 -0
  486. chia/daemon/__init__.py +0 -0
  487. chia/daemon/client.py +252 -0
  488. chia/daemon/keychain_proxy.py +502 -0
  489. chia/daemon/keychain_server.py +365 -0
  490. chia/daemon/server.py +1606 -0
  491. chia/daemon/windows_signal.py +56 -0
  492. chia/data_layer/__init__.py +0 -0
  493. chia/data_layer/data_layer.py +1291 -0
  494. chia/data_layer/data_layer_api.py +33 -0
  495. chia/data_layer/data_layer_errors.py +50 -0
  496. chia/data_layer/data_layer_server.py +170 -0
  497. chia/data_layer/data_layer_util.py +985 -0
  498. chia/data_layer/data_layer_wallet.py +1311 -0
  499. chia/data_layer/data_store.py +2267 -0
  500. chia/data_layer/dl_wallet_store.py +407 -0
  501. chia/data_layer/download_data.py +389 -0
  502. chia/data_layer/puzzles/__init__.py +0 -0
  503. chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
  504. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
  505. chia/data_layer/s3_plugin_config.yml +33 -0
  506. chia/data_layer/s3_plugin_service.py +468 -0
  507. chia/data_layer/util/__init__.py +0 -0
  508. chia/data_layer/util/benchmark.py +107 -0
  509. chia/data_layer/util/plugin.py +40 -0
  510. chia/farmer/__init__.py +0 -0
  511. chia/farmer/farmer.py +923 -0
  512. chia/farmer/farmer_api.py +820 -0
  513. chia/full_node/__init__.py +0 -0
  514. chia/full_node/bitcoin_fee_estimator.py +85 -0
  515. chia/full_node/block_height_map.py +271 -0
  516. chia/full_node/block_store.py +576 -0
  517. chia/full_node/bundle_tools.py +19 -0
  518. chia/full_node/coin_store.py +647 -0
  519. chia/full_node/fee_estimate.py +54 -0
  520. chia/full_node/fee_estimate_store.py +24 -0
  521. chia/full_node/fee_estimation.py +92 -0
  522. chia/full_node/fee_estimator.py +90 -0
  523. chia/full_node/fee_estimator_constants.py +38 -0
  524. chia/full_node/fee_estimator_interface.py +42 -0
  525. chia/full_node/fee_history.py +25 -0
  526. chia/full_node/fee_tracker.py +564 -0
  527. chia/full_node/full_node.py +3327 -0
  528. chia/full_node/full_node_api.py +2025 -0
  529. chia/full_node/full_node_store.py +1033 -0
  530. chia/full_node/hint_management.py +56 -0
  531. chia/full_node/hint_store.py +93 -0
  532. chia/full_node/mempool.py +589 -0
  533. chia/full_node/mempool_check_conditions.py +146 -0
  534. chia/full_node/mempool_manager.py +853 -0
  535. chia/full_node/pending_tx_cache.py +112 -0
  536. chia/full_node/puzzles/__init__.py +0 -0
  537. chia/full_node/puzzles/block_program_zero.clsp +14 -0
  538. chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
  539. chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
  540. chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
  541. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
  542. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
  543. chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
  544. chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
  545. chia/full_node/signage_point.py +16 -0
  546. chia/full_node/subscriptions.py +247 -0
  547. chia/full_node/sync_store.py +146 -0
  548. chia/full_node/tx_processing_queue.py +78 -0
  549. chia/full_node/util/__init__.py +0 -0
  550. chia/full_node/weight_proof.py +1720 -0
  551. chia/harvester/__init__.py +0 -0
  552. chia/harvester/harvester.py +272 -0
  553. chia/harvester/harvester_api.py +380 -0
  554. chia/introducer/__init__.py +0 -0
  555. chia/introducer/introducer.py +122 -0
  556. chia/introducer/introducer_api.py +70 -0
  557. chia/legacy/__init__.py +0 -0
  558. chia/legacy/keyring.py +155 -0
  559. chia/plot_sync/__init__.py +0 -0
  560. chia/plot_sync/delta.py +61 -0
  561. chia/plot_sync/exceptions.py +56 -0
  562. chia/plot_sync/receiver.py +386 -0
  563. chia/plot_sync/sender.py +340 -0
  564. chia/plot_sync/util.py +43 -0
  565. chia/plotters/__init__.py +0 -0
  566. chia/plotters/bladebit.py +388 -0
  567. chia/plotters/chiapos.py +63 -0
  568. chia/plotters/madmax.py +224 -0
  569. chia/plotters/plotters.py +577 -0
  570. chia/plotters/plotters_util.py +133 -0
  571. chia/plotting/__init__.py +0 -0
  572. chia/plotting/cache.py +213 -0
  573. chia/plotting/check_plots.py +283 -0
  574. chia/plotting/create_plots.py +278 -0
  575. chia/plotting/manager.py +436 -0
  576. chia/plotting/util.py +336 -0
  577. chia/pools/__init__.py +0 -0
  578. chia/pools/pool_config.py +110 -0
  579. chia/pools/pool_puzzles.py +459 -0
  580. chia/pools/pool_wallet.py +933 -0
  581. chia/pools/pool_wallet_info.py +118 -0
  582. chia/pools/puzzles/__init__.py +0 -0
  583. chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
  584. chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
  585. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
  586. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
  587. chia/protocols/__init__.py +0 -0
  588. chia/protocols/farmer_protocol.py +102 -0
  589. chia/protocols/full_node_protocol.py +219 -0
  590. chia/protocols/harvester_protocol.py +216 -0
  591. chia/protocols/introducer_protocol.py +25 -0
  592. chia/protocols/pool_protocol.py +177 -0
  593. chia/protocols/protocol_message_types.py +139 -0
  594. chia/protocols/protocol_state_machine.py +87 -0
  595. chia/protocols/protocol_timing.py +8 -0
  596. chia/protocols/shared_protocol.py +86 -0
  597. chia/protocols/timelord_protocol.py +93 -0
  598. chia/protocols/wallet_protocol.py +401 -0
  599. chia/py.typed +0 -0
  600. chia/rpc/__init__.py +0 -0
  601. chia/rpc/crawler_rpc_api.py +80 -0
  602. chia/rpc/data_layer_rpc_api.py +644 -0
  603. chia/rpc/data_layer_rpc_client.py +188 -0
  604. chia/rpc/data_layer_rpc_util.py +58 -0
  605. chia/rpc/farmer_rpc_api.py +365 -0
  606. chia/rpc/farmer_rpc_client.py +86 -0
  607. chia/rpc/full_node_rpc_api.py +959 -0
  608. chia/rpc/full_node_rpc_client.py +292 -0
  609. chia/rpc/harvester_rpc_api.py +141 -0
  610. chia/rpc/harvester_rpc_client.py +54 -0
  611. chia/rpc/rpc_client.py +164 -0
  612. chia/rpc/rpc_server.py +521 -0
  613. chia/rpc/timelord_rpc_api.py +32 -0
  614. chia/rpc/util.py +93 -0
  615. chia/rpc/wallet_request_types.py +904 -0
  616. chia/rpc/wallet_rpc_api.py +4943 -0
  617. chia/rpc/wallet_rpc_client.py +1814 -0
  618. chia/seeder/__init__.py +0 -0
  619. chia/seeder/crawl_store.py +425 -0
  620. chia/seeder/crawler.py +410 -0
  621. chia/seeder/crawler_api.py +135 -0
  622. chia/seeder/dns_server.py +593 -0
  623. chia/seeder/peer_record.py +146 -0
  624. chia/seeder/start_crawler.py +92 -0
  625. chia/server/__init__.py +0 -0
  626. chia/server/address_manager.py +658 -0
  627. chia/server/address_manager_store.py +237 -0
  628. chia/server/api_protocol.py +116 -0
  629. chia/server/capabilities.py +24 -0
  630. chia/server/chia_policy.py +346 -0
  631. chia/server/introducer_peers.py +76 -0
  632. chia/server/node_discovery.py +714 -0
  633. chia/server/outbound_message.py +33 -0
  634. chia/server/rate_limit_numbers.py +214 -0
  635. chia/server/rate_limits.py +153 -0
  636. chia/server/server.py +741 -0
  637. chia/server/signal_handlers.py +120 -0
  638. chia/server/ssl_context.py +32 -0
  639. chia/server/start_data_layer.py +151 -0
  640. chia/server/start_farmer.py +98 -0
  641. chia/server/start_full_node.py +112 -0
  642. chia/server/start_harvester.py +93 -0
  643. chia/server/start_introducer.py +81 -0
  644. chia/server/start_service.py +316 -0
  645. chia/server/start_timelord.py +89 -0
  646. chia/server/start_wallet.py +113 -0
  647. chia/server/upnp.py +118 -0
  648. chia/server/ws_connection.py +766 -0
  649. chia/simulator/__init__.py +0 -0
  650. chia/simulator/add_blocks_in_batches.py +54 -0
  651. chia/simulator/block_tools.py +2054 -0
  652. chia/simulator/full_node_simulator.py +794 -0
  653. chia/simulator/keyring.py +128 -0
  654. chia/simulator/setup_services.py +506 -0
  655. chia/simulator/simulator_constants.py +13 -0
  656. chia/simulator/simulator_full_node_rpc_api.py +99 -0
  657. chia/simulator/simulator_full_node_rpc_client.py +60 -0
  658. chia/simulator/simulator_protocol.py +29 -0
  659. chia/simulator/simulator_test_tools.py +164 -0
  660. chia/simulator/socket.py +24 -0
  661. chia/simulator/ssl_certs.py +114 -0
  662. chia/simulator/ssl_certs_1.py +697 -0
  663. chia/simulator/ssl_certs_10.py +697 -0
  664. chia/simulator/ssl_certs_2.py +697 -0
  665. chia/simulator/ssl_certs_3.py +697 -0
  666. chia/simulator/ssl_certs_4.py +697 -0
  667. chia/simulator/ssl_certs_5.py +697 -0
  668. chia/simulator/ssl_certs_6.py +697 -0
  669. chia/simulator/ssl_certs_7.py +697 -0
  670. chia/simulator/ssl_certs_8.py +697 -0
  671. chia/simulator/ssl_certs_9.py +697 -0
  672. chia/simulator/start_simulator.py +143 -0
  673. chia/simulator/wallet_tools.py +246 -0
  674. chia/ssl/__init__.py +0 -0
  675. chia/ssl/chia_ca.crt +19 -0
  676. chia/ssl/chia_ca.key +28 -0
  677. chia/ssl/create_ssl.py +249 -0
  678. chia/ssl/dst_root_ca.pem +20 -0
  679. chia/timelord/__init__.py +0 -0
  680. chia/timelord/iters_from_block.py +50 -0
  681. chia/timelord/timelord.py +1226 -0
  682. chia/timelord/timelord_api.py +138 -0
  683. chia/timelord/timelord_launcher.py +190 -0
  684. chia/timelord/timelord_state.py +244 -0
  685. chia/timelord/types.py +22 -0
  686. chia/types/__init__.py +0 -0
  687. chia/types/aliases.py +35 -0
  688. chia/types/block_protocol.py +20 -0
  689. chia/types/blockchain_format/__init__.py +0 -0
  690. chia/types/blockchain_format/classgroup.py +5 -0
  691. chia/types/blockchain_format/coin.py +28 -0
  692. chia/types/blockchain_format/foliage.py +8 -0
  693. chia/types/blockchain_format/pool_target.py +5 -0
  694. chia/types/blockchain_format/program.py +269 -0
  695. chia/types/blockchain_format/proof_of_space.py +135 -0
  696. chia/types/blockchain_format/reward_chain_block.py +6 -0
  697. chia/types/blockchain_format/serialized_program.py +5 -0
  698. chia/types/blockchain_format/sized_bytes.py +11 -0
  699. chia/types/blockchain_format/slots.py +9 -0
  700. chia/types/blockchain_format/sub_epoch_summary.py +5 -0
  701. chia/types/blockchain_format/tree_hash.py +72 -0
  702. chia/types/blockchain_format/vdf.py +86 -0
  703. chia/types/clvm_cost.py +13 -0
  704. chia/types/coin_record.py +43 -0
  705. chia/types/coin_spend.py +115 -0
  706. chia/types/condition_opcodes.py +73 -0
  707. chia/types/condition_with_args.py +16 -0
  708. chia/types/eligible_coin_spends.py +365 -0
  709. chia/types/end_of_slot_bundle.py +5 -0
  710. chia/types/fee_rate.py +38 -0
  711. chia/types/full_block.py +5 -0
  712. chia/types/generator_types.py +13 -0
  713. chia/types/header_block.py +5 -0
  714. chia/types/internal_mempool_item.py +18 -0
  715. chia/types/mempool_inclusion_status.py +9 -0
  716. chia/types/mempool_item.py +85 -0
  717. chia/types/mempool_submission_status.py +30 -0
  718. chia/types/mojos.py +7 -0
  719. chia/types/peer_info.py +64 -0
  720. chia/types/signing_mode.py +29 -0
  721. chia/types/spend_bundle.py +30 -0
  722. chia/types/spend_bundle_conditions.py +7 -0
  723. chia/types/transaction_queue_entry.py +55 -0
  724. chia/types/unfinished_block.py +5 -0
  725. chia/types/unfinished_header_block.py +37 -0
  726. chia/types/validation_state.py +14 -0
  727. chia/types/weight_proof.py +49 -0
  728. chia/util/__init__.py +0 -0
  729. chia/util/action_scope.py +168 -0
  730. chia/util/async_pool.py +226 -0
  731. chia/util/augmented_chain.py +134 -0
  732. chia/util/batches.py +42 -0
  733. chia/util/bech32m.py +126 -0
  734. chia/util/beta_metrics.py +119 -0
  735. chia/util/block_cache.py +56 -0
  736. chia/util/byte_types.py +12 -0
  737. chia/util/check_fork_next_block.py +33 -0
  738. chia/util/chia_logging.py +144 -0
  739. chia/util/chia_version.py +33 -0
  740. chia/util/collection.py +17 -0
  741. chia/util/condition_tools.py +201 -0
  742. chia/util/config.py +367 -0
  743. chia/util/cpu.py +22 -0
  744. chia/util/db_synchronous.py +23 -0
  745. chia/util/db_version.py +32 -0
  746. chia/util/db_wrapper.py +430 -0
  747. chia/util/default_root.py +27 -0
  748. chia/util/dump_keyring.py +93 -0
  749. chia/util/english.txt +2048 -0
  750. chia/util/errors.py +353 -0
  751. chia/util/file_keyring.py +469 -0
  752. chia/util/files.py +97 -0
  753. chia/util/full_block_utils.py +345 -0
  754. chia/util/generator_tools.py +72 -0
  755. chia/util/hash.py +31 -0
  756. chia/util/initial-config.yaml +694 -0
  757. chia/util/inline_executor.py +26 -0
  758. chia/util/ints.py +19 -0
  759. chia/util/ip_address.py +39 -0
  760. chia/util/json_util.py +37 -0
  761. chia/util/keychain.py +676 -0
  762. chia/util/keyring_wrapper.py +327 -0
  763. chia/util/limited_semaphore.py +41 -0
  764. chia/util/lock.py +49 -0
  765. chia/util/log_exceptions.py +32 -0
  766. chia/util/logging.py +36 -0
  767. chia/util/lru_cache.py +31 -0
  768. chia/util/math.py +20 -0
  769. chia/util/network.py +182 -0
  770. chia/util/paginator.py +48 -0
  771. chia/util/path.py +31 -0
  772. chia/util/permissions.py +20 -0
  773. chia/util/prev_transaction_block.py +21 -0
  774. chia/util/priority_mutex.py +95 -0
  775. chia/util/profiler.py +197 -0
  776. chia/util/recursive_replace.py +24 -0
  777. chia/util/safe_cancel_task.py +16 -0
  778. chia/util/service_groups.py +47 -0
  779. chia/util/setproctitle.py +22 -0
  780. chia/util/significant_bits.py +32 -0
  781. chia/util/ssl_check.py +213 -0
  782. chia/util/streamable.py +642 -0
  783. chia/util/task_referencer.py +59 -0
  784. chia/util/task_timing.py +382 -0
  785. chia/util/timing.py +67 -0
  786. chia/util/vdf_prover.py +30 -0
  787. chia/util/virtual_project_analysis.py +540 -0
  788. chia/util/ws_message.py +66 -0
  789. chia/wallet/__init__.py +0 -0
  790. chia/wallet/cat_wallet/__init__.py +0 -0
  791. chia/wallet/cat_wallet/cat_constants.py +75 -0
  792. chia/wallet/cat_wallet/cat_info.py +47 -0
  793. chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
  794. chia/wallet/cat_wallet/cat_utils.py +164 -0
  795. chia/wallet/cat_wallet/cat_wallet.py +855 -0
  796. chia/wallet/cat_wallet/dao_cat_info.py +28 -0
  797. chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
  798. chia/wallet/cat_wallet/lineage_store.py +74 -0
  799. chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
  800. chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
  801. chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
  802. chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
  803. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
  804. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
  805. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
  806. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
  807. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
  808. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
  809. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
  810. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
  811. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
  812. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
  813. chia/wallet/coin_selection.py +188 -0
  814. chia/wallet/conditions.py +1512 -0
  815. chia/wallet/dao_wallet/__init__.py +0 -0
  816. chia/wallet/dao_wallet/dao_info.py +61 -0
  817. chia/wallet/dao_wallet/dao_utils.py +811 -0
  818. chia/wallet/dao_wallet/dao_wallet.py +2119 -0
  819. chia/wallet/db_wallet/__init__.py +0 -0
  820. chia/wallet/db_wallet/db_wallet_puzzles.py +111 -0
  821. chia/wallet/derivation_record.py +30 -0
  822. chia/wallet/derive_keys.py +146 -0
  823. chia/wallet/did_wallet/__init__.py +0 -0
  824. chia/wallet/did_wallet/did_info.py +39 -0
  825. chia/wallet/did_wallet/did_wallet.py +1494 -0
  826. chia/wallet/did_wallet/did_wallet_puzzles.py +221 -0
  827. chia/wallet/did_wallet/puzzles/__init__.py +0 -0
  828. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
  829. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
  830. chia/wallet/driver_protocol.py +26 -0
  831. chia/wallet/key_val_store.py +55 -0
  832. chia/wallet/lineage_proof.py +58 -0
  833. chia/wallet/nft_wallet/__init__.py +0 -0
  834. chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
  835. chia/wallet/nft_wallet/nft_info.py +120 -0
  836. chia/wallet/nft_wallet/nft_puzzles.py +305 -0
  837. chia/wallet/nft_wallet/nft_wallet.py +1687 -0
  838. chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
  839. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  840. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
  841. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
  842. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
  843. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
  844. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
  845. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
  846. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
  847. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
  848. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
  849. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
  850. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
  851. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
  852. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
  853. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
  854. chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
  855. chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
  856. chia/wallet/nft_wallet/uncurry_nft.py +217 -0
  857. chia/wallet/notification_manager.py +117 -0
  858. chia/wallet/notification_store.py +178 -0
  859. chia/wallet/outer_puzzles.py +84 -0
  860. chia/wallet/payment.py +33 -0
  861. chia/wallet/puzzle_drivers.py +118 -0
  862. chia/wallet/puzzles/__init__.py +0 -0
  863. chia/wallet/puzzles/augmented_condition.clsp +13 -0
  864. chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
  865. chia/wallet/puzzles/clawback/__init__.py +0 -0
  866. chia/wallet/puzzles/clawback/drivers.py +188 -0
  867. chia/wallet/puzzles/clawback/metadata.py +38 -0
  868. chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
  869. chia/wallet/puzzles/condition_codes.clib +77 -0
  870. chia/wallet/puzzles/curry-and-treehash.clib +102 -0
  871. chia/wallet/puzzles/curry.clib +135 -0
  872. chia/wallet/puzzles/curry_by_index.clib +16 -0
  873. chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
  874. chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
  875. chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
  876. chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
  877. chia/wallet/puzzles/dao_finished_state.clsp +35 -0
  878. chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
  879. chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
  880. chia/wallet/puzzles/dao_lockup.clsp +288 -0
  881. chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
  882. chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
  883. chia/wallet/puzzles/dao_proposal.clsp +377 -0
  884. chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
  885. chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
  886. chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
  887. chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
  888. chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
  889. chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
  890. chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
  891. chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
  892. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
  893. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
  894. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
  895. chia/wallet/puzzles/dao_treasury.clsp +115 -0
  896. chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
  897. chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
  898. chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
  899. chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
  900. chia/wallet/puzzles/json.clib +25 -0
  901. chia/wallet/puzzles/load_clvm.py +161 -0
  902. chia/wallet/puzzles/merkle_utils.clib +18 -0
  903. chia/wallet/puzzles/notification.clsp +7 -0
  904. chia/wallet/puzzles/notification.clsp.hex +1 -0
  905. chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
  906. chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
  907. chia/wallet/puzzles/p2_conditions.clsp +3 -0
  908. chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
  909. chia/wallet/puzzles/p2_conditions.py +26 -0
  910. chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
  911. chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
  912. chia/wallet/puzzles/p2_delegated_conditions.py +21 -0
  913. chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
  914. chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
  915. chia/wallet/puzzles/p2_delegated_puzzle.py +34 -0
  916. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
  917. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
  918. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +160 -0
  919. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
  920. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
  921. chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +21 -0
  922. chia/wallet/puzzles/p2_parent.clsp +19 -0
  923. chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
  924. chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
  925. chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
  926. chia/wallet/puzzles/p2_puzzle_hash.py +27 -0
  927. chia/wallet/puzzles/p2_singleton.clsp +30 -0
  928. chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
  929. chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
  930. chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
  931. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
  932. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
  933. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
  934. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
  935. chia/wallet/puzzles/puzzle_utils.py +34 -0
  936. chia/wallet/puzzles/settlement_payments.clsp +49 -0
  937. chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
  938. chia/wallet/puzzles/sha256tree.clib +11 -0
  939. chia/wallet/puzzles/singleton_launcher.clsp +16 -0
  940. chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
  941. chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
  942. chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
  943. chia/wallet/puzzles/singleton_top_layer.py +296 -0
  944. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
  945. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
  946. chia/wallet/puzzles/singleton_top_layer_v1_1.py +345 -0
  947. chia/wallet/puzzles/singleton_truths.clib +21 -0
  948. chia/wallet/puzzles/tails.py +348 -0
  949. chia/wallet/puzzles/utility_macros.clib +48 -0
  950. chia/wallet/signer_protocol.py +125 -0
  951. chia/wallet/singleton.py +106 -0
  952. chia/wallet/singleton_record.py +30 -0
  953. chia/wallet/trade_manager.py +1102 -0
  954. chia/wallet/trade_record.py +67 -0
  955. chia/wallet/trading/__init__.py +0 -0
  956. chia/wallet/trading/offer.py +702 -0
  957. chia/wallet/trading/trade_status.py +13 -0
  958. chia/wallet/trading/trade_store.py +526 -0
  959. chia/wallet/transaction_record.py +158 -0
  960. chia/wallet/transaction_sorting.py +14 -0
  961. chia/wallet/uncurried_puzzle.py +17 -0
  962. chia/wallet/util/__init__.py +0 -0
  963. chia/wallet/util/address_type.py +55 -0
  964. chia/wallet/util/blind_signer_tl.py +164 -0
  965. chia/wallet/util/clvm_streamable.py +203 -0
  966. chia/wallet/util/compute_hints.py +66 -0
  967. chia/wallet/util/compute_memos.py +43 -0
  968. chia/wallet/util/curry_and_treehash.py +91 -0
  969. chia/wallet/util/debug_spend_bundle.py +232 -0
  970. chia/wallet/util/merkle_tree.py +100 -0
  971. chia/wallet/util/merkle_utils.py +102 -0
  972. chia/wallet/util/new_peak_queue.py +82 -0
  973. chia/wallet/util/notifications.py +12 -0
  974. chia/wallet/util/peer_request_cache.py +174 -0
  975. chia/wallet/util/pprint.py +39 -0
  976. chia/wallet/util/puzzle_compression.py +95 -0
  977. chia/wallet/util/puzzle_decorator.py +100 -0
  978. chia/wallet/util/puzzle_decorator_type.py +7 -0
  979. chia/wallet/util/query_filter.py +59 -0
  980. chia/wallet/util/transaction_type.py +23 -0
  981. chia/wallet/util/tx_config.py +158 -0
  982. chia/wallet/util/wallet_sync_utils.py +351 -0
  983. chia/wallet/util/wallet_types.py +72 -0
  984. chia/wallet/vc_wallet/__init__.py +0 -0
  985. chia/wallet/vc_wallet/cr_cat_drivers.py +664 -0
  986. chia/wallet/vc_wallet/cr_cat_wallet.py +877 -0
  987. chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
  988. chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
  989. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
  990. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
  991. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
  992. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
  993. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
  994. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
  995. chia/wallet/vc_wallet/vc_drivers.py +838 -0
  996. chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
  997. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
  998. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
  999. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
  1000. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
  1001. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
  1002. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
  1003. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
  1004. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
  1005. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
  1006. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
  1007. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
  1008. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
  1009. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
  1010. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
  1011. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
  1012. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
  1013. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
  1014. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
  1015. chia/wallet/vc_wallet/vc_store.py +263 -0
  1016. chia/wallet/vc_wallet/vc_wallet.py +638 -0
  1017. chia/wallet/wallet.py +698 -0
  1018. chia/wallet/wallet_action_scope.py +96 -0
  1019. chia/wallet/wallet_blockchain.py +244 -0
  1020. chia/wallet/wallet_coin_record.py +72 -0
  1021. chia/wallet/wallet_coin_store.py +351 -0
  1022. chia/wallet/wallet_info.py +35 -0
  1023. chia/wallet/wallet_interested_store.py +188 -0
  1024. chia/wallet/wallet_nft_store.py +279 -0
  1025. chia/wallet/wallet_node.py +1765 -0
  1026. chia/wallet/wallet_node_api.py +207 -0
  1027. chia/wallet/wallet_pool_store.py +119 -0
  1028. chia/wallet/wallet_protocol.py +90 -0
  1029. chia/wallet/wallet_puzzle_store.py +396 -0
  1030. chia/wallet/wallet_retry_store.py +70 -0
  1031. chia/wallet/wallet_singleton_store.py +259 -0
  1032. chia/wallet/wallet_spend_bundle.py +25 -0
  1033. chia/wallet/wallet_state_manager.py +2819 -0
  1034. chia/wallet/wallet_transaction_store.py +496 -0
  1035. chia/wallet/wallet_user_store.py +110 -0
  1036. chia/wallet/wallet_weight_proof_handler.py +126 -0
  1037. chia_blockchain-2.5.1rc1.dist-info/LICENSE +201 -0
  1038. chia_blockchain-2.5.1rc1.dist-info/METADATA +156 -0
  1039. chia_blockchain-2.5.1rc1.dist-info/RECORD +1042 -0
  1040. chia_blockchain-2.5.1rc1.dist-info/WHEEL +4 -0
  1041. chia_blockchain-2.5.1rc1.dist-info/entry_points.txt +17 -0
  1042. mozilla-ca/cacert.pem +3611 -0
@@ -0,0 +1,3153 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import dataclasses
5
+ import io
6
+ import json
7
+ import logging
8
+ import random
9
+ from operator import attrgetter
10
+ from typing import Any, Optional, cast
11
+ from unittest.mock import patch
12
+
13
+ import aiosqlite
14
+ import pytest
15
+ from chia_rs import G1Element, G2Element
16
+
17
+ from chia._tests.environments.wallet import WalletStateTransition, WalletTestFramework
18
+ from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_not_none
19
+ from chia._tests.wallet.test_wallet_coin_store import (
20
+ get_coin_records_amount_filter_tests,
21
+ get_coin_records_amount_range_tests,
22
+ get_coin_records_coin_id_filter_tests,
23
+ get_coin_records_coin_type_tests,
24
+ get_coin_records_confirmed_range_tests,
25
+ get_coin_records_include_total_count_tests,
26
+ get_coin_records_mixed_tests,
27
+ get_coin_records_offset_limit_tests,
28
+ get_coin_records_order_tests,
29
+ get_coin_records_parent_coin_id_filter_tests,
30
+ get_coin_records_puzzle_hash_filter_tests,
31
+ get_coin_records_reverse_tests,
32
+ get_coin_records_spent_range_tests,
33
+ get_coin_records_wallet_id_tests,
34
+ get_coin_records_wallet_type_tests,
35
+ record_1,
36
+ record_2,
37
+ record_3,
38
+ record_4,
39
+ record_5,
40
+ record_6,
41
+ record_7,
42
+ record_8,
43
+ record_9,
44
+ )
45
+ from chia.cmds.coins import CombineCMD, SplitCMD
46
+ from chia.cmds.param_types import CliAmount
47
+ from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
48
+ from chia.consensus.coinbase import create_puzzlehash_for_pk
49
+ from chia.rpc.full_node_rpc_client import FullNodeRpcClient
50
+ from chia.rpc.rpc_client import ResponseFailureError
51
+ from chia.rpc.rpc_server import RpcServer
52
+ from chia.rpc.wallet_request_types import (
53
+ AddKey,
54
+ CheckDeleteKey,
55
+ CombineCoins,
56
+ DefaultCAT,
57
+ DeleteKey,
58
+ DIDGetPubkey,
59
+ GetNotifications,
60
+ GetPrivateKey,
61
+ GetSyncStatusResponse,
62
+ GetTimestampForHeight,
63
+ LogIn,
64
+ PushTransactions,
65
+ PushTX,
66
+ SetWalletResyncOnStartup,
67
+ SplitCoins,
68
+ VerifySignature,
69
+ VerifySignatureResponse,
70
+ )
71
+ from chia.rpc.wallet_rpc_api import WalletRpcApi
72
+ from chia.rpc.wallet_rpc_client import WalletRpcClient
73
+ from chia.server.server import ChiaServer
74
+ from chia.server.start_service import Service
75
+ from chia.simulator.full_node_simulator import FullNodeSimulator
76
+ from chia.simulator.simulator_protocol import FarmNewBlockProtocol
77
+ from chia.types.blockchain_format.coin import Coin, coin_as_list
78
+ from chia.types.blockchain_format.program import Program
79
+ from chia.types.blockchain_format.sized_bytes import bytes32
80
+ from chia.types.coin_record import CoinRecord
81
+ from chia.types.coin_spend import CoinSpend, make_spend
82
+ from chia.types.peer_info import PeerInfo
83
+ from chia.types.signing_mode import SigningMode
84
+ from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
85
+ from chia.util.config import load_config, lock_and_load_config, save_config
86
+ from chia.util.db_wrapper import DBWrapper2
87
+ from chia.util.hash import std_hash
88
+ from chia.util.ints import uint16, uint32, uint64
89
+ from chia.util.streamable import ConversionError, InvalidTypeError
90
+ from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS
91
+ from chia.wallet.cat_wallet.cat_utils import CAT_MOD, construct_cat_puzzle
92
+ from chia.wallet.cat_wallet.cat_wallet import CATWallet
93
+ from chia.wallet.conditions import (
94
+ ConditionValidTimes,
95
+ CreateCoinAnnouncement,
96
+ CreatePuzzleAnnouncement,
97
+ Remark,
98
+ conditions_to_json_dicts,
99
+ )
100
+ from chia.wallet.derive_keys import master_sk_to_wallet_sk, master_sk_to_wallet_sk_unhardened
101
+ from chia.wallet.did_wallet.did_wallet import DIDWallet
102
+ from chia.wallet.nft_wallet.nft_wallet import NFTWallet
103
+ from chia.wallet.puzzles.clawback.metadata import AutoClaimSettings
104
+ from chia.wallet.signer_protocol import UnsignedTransaction
105
+ from chia.wallet.trading.trade_status import TradeStatus
106
+ from chia.wallet.transaction_record import TransactionRecord
107
+ from chia.wallet.transaction_sorting import SortKey
108
+ from chia.wallet.uncurried_puzzle import uncurry_puzzle
109
+ from chia.wallet.util.address_type import AddressType
110
+ from chia.wallet.util.blind_signer_tl import BLIND_SIGNER_TRANSLATION
111
+ from chia.wallet.util.clvm_streamable import byte_deserialize_clvm_streamable
112
+ from chia.wallet.util.compute_memos import compute_memos
113
+ from chia.wallet.util.query_filter import AmountFilter, HashFilter, TransactionTypeFilter
114
+ from chia.wallet.util.transaction_type import TransactionType
115
+ from chia.wallet.util.tx_config import DEFAULT_COIN_SELECTION_CONFIG, DEFAULT_TX_CONFIG
116
+ from chia.wallet.util.wallet_types import CoinType, WalletType
117
+ from chia.wallet.wallet import Wallet
118
+ from chia.wallet.wallet_coin_record import WalletCoinRecord
119
+ from chia.wallet.wallet_coin_store import GetCoinRecords
120
+ from chia.wallet.wallet_node import WalletNode
121
+ from chia.wallet.wallet_protocol import WalletProtocol
122
+ from chia.wallet.wallet_spend_bundle import WalletSpendBundle
123
+
124
+ log = logging.getLogger(__name__)
125
+
126
+
127
+ @dataclasses.dataclass
128
+ class WalletBundle:
129
+ service: Service
130
+ node: WalletNode
131
+ rpc_client: WalletRpcClient
132
+ wallet: Wallet
133
+
134
+
135
+ @dataclasses.dataclass
136
+ class FullNodeBundle:
137
+ server: ChiaServer
138
+ api: FullNodeSimulator
139
+ rpc_client: FullNodeRpcClient
140
+
141
+
142
+ @dataclasses.dataclass
143
+ class WalletRpcTestEnvironment:
144
+ wallet_1: WalletBundle
145
+ wallet_2: WalletBundle
146
+ full_node: FullNodeBundle
147
+
148
+
149
+ async def check_client_synced(wallet_client: WalletRpcClient) -> bool:
150
+ return (await wallet_client.get_sync_status()).synced
151
+
152
+
153
+ async def farm_transaction_block(full_node_api: FullNodeSimulator, wallet_node: WalletNode):
154
+ await full_node_api.farm_blocks_to_puzzlehash(count=1)
155
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
156
+
157
+
158
+ def check_mempool_spend_count(full_node_api: FullNodeSimulator, num_of_spends):
159
+ return full_node_api.full_node.mempool_manager.mempool.size() == num_of_spends
160
+
161
+
162
+ async def farm_transaction(full_node_api: FullNodeSimulator, wallet_node: WalletNode, spend_bundle: WalletSpendBundle):
163
+ await time_out_assert(
164
+ 20, full_node_api.full_node.mempool_manager.get_spendbundle, spend_bundle, spend_bundle.name()
165
+ )
166
+ await farm_transaction_block(full_node_api, wallet_node)
167
+ assert full_node_api.full_node.mempool_manager.get_spendbundle(spend_bundle.name()) is None
168
+
169
+
170
+ async def generate_funds(full_node_api: FullNodeSimulator, wallet_bundle: WalletBundle, num_blocks: int = 1):
171
+ wallet_id = 1
172
+ initial_balances = await wallet_bundle.rpc_client.get_wallet_balance(wallet_id)
173
+ ph: bytes32 = decode_puzzle_hash(await wallet_bundle.rpc_client.get_next_address(wallet_id, True))
174
+ generated_funds = 0
175
+ for i in range(0, num_blocks):
176
+ await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
177
+ peak_height = full_node_api.full_node.blockchain.get_peak_height()
178
+ assert peak_height is not None
179
+ generated_funds += calculate_pool_reward(peak_height) + calculate_base_farmer_reward(peak_height)
180
+
181
+ # Farm a dummy block to confirm the created funds
182
+ await farm_transaction_block(full_node_api, wallet_bundle.node)
183
+
184
+ expected_confirmed = initial_balances["confirmed_wallet_balance"] + generated_funds
185
+ expected_unconfirmed = initial_balances["unconfirmed_wallet_balance"] + generated_funds
186
+ await time_out_assert(20, get_confirmed_balance, expected_confirmed, wallet_bundle.rpc_client, wallet_id)
187
+ await time_out_assert(20, get_unconfirmed_balance, expected_unconfirmed, wallet_bundle.rpc_client, wallet_id)
188
+ await time_out_assert(20, check_client_synced, True, wallet_bundle.rpc_client)
189
+
190
+ return generated_funds
191
+
192
+
193
+ @pytest.fixture(scope="function", params=[True, False])
194
+ async def wallet_rpc_environment(two_wallet_nodes_services, request, self_hostname):
195
+ full_node, wallets, bt = two_wallet_nodes_services
196
+ full_node_service = full_node[0]
197
+ full_node_api = full_node_service._api
198
+ full_node_server = full_node_api.full_node.server
199
+ wallet_service = wallets[0]
200
+ wallet_service_2 = wallets[1]
201
+ wallet_node = wallet_service._node
202
+ wallet_node_2 = wallet_service_2._node
203
+ wallet = wallet_node.wallet_state_manager.main_wallet
204
+ wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
205
+
206
+ config = bt.config
207
+ hostname = config["self_hostname"]
208
+
209
+ if request.param:
210
+ wallet_node.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
211
+ wallet_node_2.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
212
+ else:
213
+ wallet_node.config["trusted_peers"] = {}
214
+ wallet_node_2.config["trusted_peers"] = {}
215
+
216
+ await wallet_node.server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
217
+ await wallet_node_2.server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
218
+
219
+ async with WalletRpcClient.create_as_context(
220
+ hostname, wallet_service.rpc_server.listen_port, wallet_service.root_path, wallet_service.config
221
+ ) as client:
222
+ async with WalletRpcClient.create_as_context(
223
+ hostname, wallet_service_2.rpc_server.listen_port, wallet_service_2.root_path, wallet_service_2.config
224
+ ) as client_2:
225
+ async with FullNodeRpcClient.create_as_context(
226
+ hostname,
227
+ full_node_service.rpc_server.listen_port,
228
+ full_node_service.root_path,
229
+ full_node_service.config,
230
+ ) as client_node:
231
+ wallet_bundle_1: WalletBundle = WalletBundle(wallet_service, wallet_node, client, wallet)
232
+ wallet_bundle_2: WalletBundle = WalletBundle(wallet_service_2, wallet_node_2, client_2, wallet_2)
233
+ node_bundle: FullNodeBundle = FullNodeBundle(full_node_server, full_node_api, client_node)
234
+
235
+ yield WalletRpcTestEnvironment(wallet_bundle_1, wallet_bundle_2, node_bundle)
236
+
237
+
238
+ async def create_tx_outputs(wallet: Wallet, output_args: list[tuple[int, Optional[list[str]]]]) -> list[dict[str, Any]]:
239
+ outputs = []
240
+ for args in output_args:
241
+ output = {"amount": uint64(args[0]), "puzzle_hash": await wallet.get_new_puzzlehash()}
242
+ if args[1] is not None:
243
+ assert len(args[1]) > 0
244
+ output["memos"] = args[1]
245
+ outputs.append(output)
246
+ return outputs
247
+
248
+
249
+ async def assert_wallet_types(client: WalletRpcClient, expected: dict[WalletType, int]) -> None:
250
+ for wallet_type in WalletType:
251
+ wallets = await client.get_wallets(wallet_type)
252
+ wallet_count = len(wallets)
253
+ if wallet_type in expected:
254
+ assert wallet_count == expected.get(wallet_type, 0)
255
+ for wallet in wallets:
256
+ assert wallet["type"] == wallet_type.value
257
+
258
+
259
+ def assert_tx_amounts(
260
+ tx: TransactionRecord,
261
+ outputs: list[dict[str, Any]],
262
+ *,
263
+ amount_fee: uint64,
264
+ change_expected: bool,
265
+ is_cat: bool = False,
266
+ ) -> None:
267
+ assert tx.fee_amount == amount_fee
268
+ assert tx.amount == sum(output["amount"] for output in outputs)
269
+ expected_additions = len(outputs) + 1 if change_expected else len(outputs)
270
+ assert len(tx.additions) == expected_additions
271
+ addition_amounts = [addition.amount for addition in tx.additions]
272
+ removal_amounts = [removal.amount for removal in tx.removals]
273
+ for output in outputs:
274
+ assert output["amount"] in addition_amounts
275
+ if is_cat:
276
+ assert (sum(removal_amounts) - sum(addition_amounts)) == 0
277
+ else:
278
+ assert (sum(removal_amounts) - sum(addition_amounts)) == amount_fee
279
+
280
+
281
+ async def assert_push_tx_error(node_rpc: FullNodeRpcClient, tx: TransactionRecord):
282
+ spend_bundle = tx.spend_bundle
283
+ assert spend_bundle is not None
284
+ # check error for a ASSERT_ANNOUNCE_CONSUMED_FAILED and if the error is not there throw a value error
285
+ try:
286
+ await node_rpc.push_tx(spend_bundle)
287
+ except ValueError as error:
288
+ error_string = error.args[0]["error"]
289
+ if error_string.find("ASSERT_ANNOUNCE_CONSUMED_FAILED") == -1:
290
+ raise ValueError from error
291
+
292
+
293
+ async def assert_get_balance(rpc_client: WalletRpcClient, wallet_node: WalletNode, wallet: WalletProtocol) -> None:
294
+ expected_balance = await wallet_node.get_balance(wallet.id())
295
+ expected_balance_dict = expected_balance.to_json_dict()
296
+ expected_balance_dict["wallet_id"] = wallet.id()
297
+ expected_balance_dict["wallet_type"] = wallet.type()
298
+ expected_balance_dict["fingerprint"] = wallet_node.logged_in_fingerprint
299
+ if wallet.type() in {WalletType.CAT, WalletType.CRCAT}:
300
+ assert isinstance(wallet, CATWallet)
301
+ expected_balance_dict["asset_id"] = wallet.get_asset_id()
302
+ assert await rpc_client.get_wallet_balance(wallet.id()) == expected_balance_dict
303
+
304
+
305
+ async def tx_in_mempool(client: WalletRpcClient, transaction_id: bytes32):
306
+ tx = await client.get_transaction(transaction_id)
307
+ return tx.is_in_mempool()
308
+
309
+
310
+ async def get_confirmed_balance(client: WalletRpcClient, wallet_id: int):
311
+ return (await client.get_wallet_balance(wallet_id))["confirmed_wallet_balance"]
312
+
313
+
314
+ async def get_unconfirmed_balance(client: WalletRpcClient, wallet_id: int):
315
+ return (await client.get_wallet_balance(wallet_id))["unconfirmed_wallet_balance"]
316
+
317
+
318
+ @pytest.mark.anyio
319
+ async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment):
320
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
321
+
322
+ wallet_2: Wallet = env.wallet_2.wallet
323
+ wallet_node: WalletNode = env.wallet_1.node
324
+ full_node_api: FullNodeSimulator = env.full_node.api
325
+ client: WalletRpcClient = env.wallet_1.rpc_client
326
+
327
+ generated_funds = await generate_funds(full_node_api, env.wallet_1)
328
+
329
+ addr = encode_puzzle_hash(await wallet_2.get_new_puzzlehash(), "txch")
330
+ tx_amount = uint64(15600000)
331
+ with pytest.raises(ValueError):
332
+ await client.send_transaction(1, uint64(100000000000000001), addr, DEFAULT_TX_CONFIG)
333
+
334
+ # Tests sending a basic transaction
335
+ extra_conditions = (Remark(Program.to(("test", None))),)
336
+ non_existent_coin = Coin(bytes32.zeros, bytes32.zeros, uint64(0))
337
+ tx_no_push = (
338
+ await client.send_transaction(
339
+ 1,
340
+ tx_amount,
341
+ addr,
342
+ memos=["this is a basic tx"],
343
+ tx_config=DEFAULT_TX_CONFIG.override(
344
+ excluded_coin_amounts=[uint64(250000000000)],
345
+ excluded_coin_ids=[non_existent_coin.name()],
346
+ reuse_puzhash=True,
347
+ ),
348
+ extra_conditions=extra_conditions,
349
+ push=False,
350
+ )
351
+ ).transaction
352
+ response = await client.fetch(
353
+ "send_transaction",
354
+ {
355
+ "wallet_id": 1,
356
+ "amount": tx_amount,
357
+ "address": addr,
358
+ "fee": 0,
359
+ "memos": ["this is a basic tx"],
360
+ "puzzle_decorator": None,
361
+ "extra_conditions": conditions_to_json_dicts(extra_conditions),
362
+ "exclude_coin_amounts": [250000000000],
363
+ "exclude_coins": [non_existent_coin.to_json_dict()],
364
+ "reuse_puzhash": True,
365
+ "CHIP-0029": True,
366
+ "translation": "CHIP-0028",
367
+ "push": True,
368
+ },
369
+ )
370
+ assert response["success"]
371
+ tx = TransactionRecord.from_json_dict_convenience(response["transactions"][0])
372
+ [
373
+ byte_deserialize_clvm_streamable(
374
+ bytes.fromhex(utx), UnsignedTransaction, translation_layer=BLIND_SIGNER_TRANSLATION
375
+ )
376
+ for utx in response["unsigned_transactions"]
377
+ ]
378
+ assert tx == dataclasses.replace(tx_no_push, created_at_time=tx.created_at_time)
379
+ transaction_id = tx.name
380
+ spend_bundle = tx.spend_bundle
381
+ assert spend_bundle is not None
382
+
383
+ await time_out_assert(20, tx_in_mempool, True, client, transaction_id)
384
+ await time_out_assert(20, get_unconfirmed_balance, generated_funds - tx_amount, client, 1)
385
+
386
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
387
+
388
+ # Checks that the memo can be retrieved
389
+ tx_confirmed = await client.get_transaction(transaction_id)
390
+ assert tx_confirmed.confirmed
391
+ assert len(tx_confirmed.get_memos()) == 1
392
+ assert [b"this is a basic tx"] in tx_confirmed.get_memos().values()
393
+ assert next(iter(tx_confirmed.get_memos().keys())) in [a.name() for a in spend_bundle.additions()]
394
+
395
+ await time_out_assert(20, get_confirmed_balance, generated_funds - tx_amount, client, 1)
396
+
397
+
398
+ @pytest.mark.anyio
399
+ async def test_push_transactions(wallet_rpc_environment: WalletRpcTestEnvironment):
400
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
401
+
402
+ wallet: Wallet = env.wallet_1.wallet
403
+ wallet_node: WalletNode = env.wallet_1.node
404
+ full_node_api: FullNodeSimulator = env.full_node.api
405
+ client: WalletRpcClient = env.wallet_1.rpc_client
406
+
407
+ await generate_funds(full_node_api, env.wallet_1, num_blocks=2)
408
+
409
+ outputs = await create_tx_outputs(wallet, [(1234321, None)])
410
+
411
+ tx = (
412
+ await client.create_signed_transactions(
413
+ outputs,
414
+ tx_config=DEFAULT_TX_CONFIG,
415
+ fee=uint64(100),
416
+ )
417
+ ).signed_tx
418
+
419
+ resp_client = await client.push_transactions(
420
+ PushTransactions(transactions=[tx], fee=uint64(10)),
421
+ DEFAULT_TX_CONFIG,
422
+ )
423
+ resp = await client.fetch(
424
+ "push_transactions", {"transactions": [tx.to_json_dict_convenience(wallet_node.config)], "fee": 10}
425
+ )
426
+ assert resp["success"]
427
+ resp = await client.fetch("push_transactions", {"transactions": [bytes(tx).hex()], "fee": 10})
428
+ assert resp["success"]
429
+
430
+ spend_bundle = WalletSpendBundle.aggregate(
431
+ [tx.spend_bundle for tx in resp_client.transactions if tx.spend_bundle is not None]
432
+ )
433
+ assert spend_bundle is not None
434
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
435
+
436
+ for tx in resp_client.transactions:
437
+ assert (await client.get_transaction(transaction_id=tx.name)).confirmed
438
+
439
+ # Just testing NOT failure here really (parsing)
440
+ await client.push_tx(PushTX(spend_bundle))
441
+ resp = await client.fetch("push_tx", {"spend_bundle": bytes(spend_bundle).hex()})
442
+ assert resp["success"]
443
+
444
+
445
+ @pytest.mark.anyio
446
+ async def test_get_balance(wallet_rpc_environment: WalletRpcTestEnvironment):
447
+ env = wallet_rpc_environment
448
+ wallet: Wallet = env.wallet_1.wallet
449
+ wallet_node: WalletNode = env.wallet_1.node
450
+ full_node_api: FullNodeSimulator = env.full_node.api
451
+ wallet_rpc_client = env.wallet_1.rpc_client
452
+ await full_node_api.farm_blocks_to_wallet(2, wallet)
453
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
454
+ cat_wallet = await CATWallet.create_new_cat_wallet(
455
+ wallet_node.wallet_state_manager,
456
+ wallet,
457
+ {"identifier": "genesis_by_id"},
458
+ uint64(100),
459
+ action_scope,
460
+ )
461
+ await full_node_api.wait_transaction_records_entered_mempool(action_scope.side_effects.transactions)
462
+ await full_node_api.wait_for_wallet_synced(wallet_node)
463
+ await assert_get_balance(wallet_rpc_client, wallet_node, wallet)
464
+ await assert_get_balance(wallet_rpc_client, wallet_node, cat_wallet)
465
+
466
+
467
+ @pytest.mark.anyio
468
+ async def test_get_farmed_amount(wallet_rpc_environment: WalletRpcTestEnvironment):
469
+ env = wallet_rpc_environment
470
+ wallet: Wallet = env.wallet_1.wallet
471
+ full_node_api: FullNodeSimulator = env.full_node.api
472
+ wallet_rpc_client = env.wallet_1.rpc_client
473
+ await full_node_api.farm_blocks_to_wallet(2, wallet)
474
+
475
+ get_farmed_amount_result = await wallet_rpc_client.get_farmed_amount()
476
+ get_timestamp_for_height_result = await wallet_rpc_client.get_timestamp_for_height(
477
+ GetTimestampForHeight(uint32(3))
478
+ ) # genesis + 2
479
+
480
+ expected_result = {
481
+ "blocks_won": 2,
482
+ "farmed_amount": 4_000_000_000_000,
483
+ "farmer_reward_amount": 500_000_000_000,
484
+ "fee_amount": 0,
485
+ "last_height_farmed": 3,
486
+ "last_time_farmed": get_timestamp_for_height_result.timestamp,
487
+ "pool_reward_amount": 3_500_000_000_000,
488
+ "success": True,
489
+ }
490
+ assert get_farmed_amount_result == expected_result
491
+
492
+
493
+ @pytest.mark.anyio
494
+ async def test_get_farmed_amount_with_fee(wallet_rpc_environment: WalletRpcTestEnvironment):
495
+ env = wallet_rpc_environment
496
+ wallet: Wallet = env.wallet_1.wallet
497
+ full_node_api: FullNodeSimulator = env.full_node.api
498
+ wallet_rpc_client = env.wallet_1.rpc_client
499
+ wallet_node: WalletNode = env.wallet_1.node
500
+
501
+ await generate_funds(full_node_api, env.wallet_1)
502
+
503
+ fee_amount = 100
504
+ async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
505
+ await wallet.generate_signed_transaction(
506
+ amount=uint64(5),
507
+ puzzle_hash=bytes32.zeros,
508
+ action_scope=action_scope,
509
+ fee=uint64(fee_amount),
510
+ )
511
+
512
+ our_ph = await wallet.get_new_puzzlehash()
513
+ await full_node_api.wait_transaction_records_entered_mempool(records=action_scope.side_effects.transactions)
514
+ await full_node_api.farm_blocks_to_puzzlehash(count=2, farm_to=our_ph, guarantee_transaction_blocks=True)
515
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
516
+
517
+ result = await wallet_rpc_client.get_farmed_amount()
518
+ assert result["fee_amount"] == fee_amount
519
+
520
+
521
+ @pytest.mark.anyio
522
+ async def test_get_timestamp_for_height(wallet_rpc_environment: WalletRpcTestEnvironment):
523
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
524
+
525
+ full_node_api: FullNodeSimulator = env.full_node.api
526
+ client: WalletRpcClient = env.wallet_1.rpc_client
527
+
528
+ await generate_funds(full_node_api, env.wallet_1)
529
+
530
+ # This tests that the client returns successfully, rather than raising or returning something unexpected
531
+ await client.get_timestamp_for_height(GetTimestampForHeight(uint32(1)))
532
+
533
+
534
+ @pytest.mark.parametrize(
535
+ "output_args, fee, select_coin, is_cat",
536
+ [
537
+ ([(348026, None)], 0, False, False),
538
+ ([(1270495230, ["memo_1"]), (902347, ["memo_2"])], 1, True, False),
539
+ ([(84920, ["memo_1_0", "memo_1_1"]), (1, ["memo_2_0"])], 0, False, False),
540
+ (
541
+ [(32058710, ["memo_1_0", "memo_1_1"]), (1, ["memo_2_0"]), (923, ["memo_3_0", "memo_3_1"])],
542
+ 32804,
543
+ True,
544
+ False,
545
+ ),
546
+ ([(1337, ["LEET"]), (81000, ["pingwei"])], 817, False, True),
547
+ ([(120000000000, None), (120000000000, None)], 10000000000, True, False),
548
+ ],
549
+ )
550
+ @pytest.mark.anyio
551
+ async def test_create_signed_transaction(
552
+ wallet_rpc_environment: WalletRpcTestEnvironment,
553
+ output_args: list[tuple[int, Optional[list[str]]]],
554
+ fee: int,
555
+ select_coin: bool,
556
+ is_cat: bool,
557
+ ):
558
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
559
+
560
+ wallet_2: Wallet = env.wallet_2.wallet
561
+ wallet_1_node: WalletNode = env.wallet_1.node
562
+ wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
563
+ full_node_api: FullNodeSimulator = env.full_node.api
564
+ full_node_rpc: FullNodeRpcClient = env.full_node.rpc_client
565
+
566
+ generated_funds = await generate_funds(full_node_api, env.wallet_1)
567
+
568
+ wallet_id = 1
569
+ if is_cat:
570
+ generated_funds = 10**9
571
+
572
+ res = await wallet_1_rpc.create_new_cat_and_wallet(uint64(generated_funds), test=True)
573
+ assert res["success"]
574
+ wallet_id = res["wallet_id"]
575
+
576
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
577
+ for i in range(5):
578
+ if check_mempool_spend_count(full_node_api, 0):
579
+ break
580
+ await farm_transaction_block(full_node_api, wallet_1_node)
581
+
582
+ outputs = await create_tx_outputs(wallet_2, output_args)
583
+ amount_outputs = sum(output["amount"] for output in outputs)
584
+ amount_fee = uint64(fee)
585
+
586
+ if is_cat:
587
+ amount_total = amount_outputs
588
+ else:
589
+ amount_total = amount_outputs + amount_fee
590
+
591
+ selected_coin = None
592
+ if select_coin:
593
+ selected_coin = await wallet_1_rpc.select_coins(
594
+ amount=amount_total, wallet_id=wallet_id, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
595
+ )
596
+ assert len(selected_coin) == 1
597
+
598
+ txs = (
599
+ await wallet_1_rpc.create_signed_transactions(
600
+ outputs,
601
+ coins=selected_coin,
602
+ fee=amount_fee,
603
+ wallet_id=wallet_id,
604
+ # shouldn't actually block it
605
+ tx_config=DEFAULT_TX_CONFIG.override(
606
+ excluded_coin_amounts=[uint64(selected_coin[0].amount)] if selected_coin is not None else [],
607
+ ),
608
+ push=True,
609
+ )
610
+ ).transactions
611
+ change_expected = not selected_coin or selected_coin[0].amount - amount_total > 0
612
+ assert_tx_amounts(txs[-1], outputs, amount_fee=amount_fee, change_expected=change_expected, is_cat=is_cat)
613
+
614
+ # Farm the transaction and make sure the wallet balance reflects it correct
615
+ spend_bundle = txs[0].spend_bundle
616
+ assert spend_bundle is not None
617
+ await farm_transaction(full_node_api, wallet_1_node, spend_bundle)
618
+ await time_out_assert(20, get_confirmed_balance, generated_funds - amount_total, wallet_1_rpc, wallet_id)
619
+
620
+ # Assert every coin comes from the same parent
621
+ additions: list[Coin] = spend_bundle.additions()
622
+ assert len({c.parent_coin_info for c in additions}) == 2 if is_cat else 1
623
+
624
+ # Assert you can get the spend for each addition
625
+ for addition in additions:
626
+ cr: Optional[CoinRecord] = await full_node_rpc.get_coin_record_by_name(addition.name())
627
+ assert cr is not None
628
+ spend: Optional[CoinSpend] = await full_node_rpc.get_puzzle_and_solution(
629
+ addition.parent_coin_info, cr.confirmed_block_index
630
+ )
631
+ assert spend is not None
632
+
633
+ # Assert the memos are all correct
634
+ addition_dict: dict[bytes32, Coin] = {addition.name(): addition for addition in additions}
635
+ memo_dictionary: dict[bytes32, list[bytes]] = compute_memos(spend_bundle)
636
+ for output in outputs:
637
+ if "memos" in output:
638
+ found: bool = False
639
+ for addition_id, addition in addition_dict.items():
640
+ if (
641
+ is_cat
642
+ and addition.amount == output["amount"]
643
+ and memo_dictionary[addition_id][0] == output["puzzle_hash"]
644
+ and memo_dictionary[addition_id][1:] == [memo.encode() for memo in output["memos"]]
645
+ ) or (
646
+ addition.amount == output["amount"]
647
+ and addition.puzzle_hash == output["puzzle_hash"]
648
+ and memo_dictionary[addition_id] == [memo.encode() for memo in output["memos"]]
649
+ ):
650
+ found = True
651
+ assert found
652
+
653
+
654
+ @pytest.mark.anyio
655
+ async def test_create_signed_transaction_with_coin_announcement(wallet_rpc_environment: WalletRpcTestEnvironment):
656
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
657
+
658
+ wallet_2: Wallet = env.wallet_2.wallet
659
+ full_node_api: FullNodeSimulator = env.full_node.api
660
+ client: WalletRpcClient = env.wallet_1.rpc_client
661
+ client_node: FullNodeRpcClient = env.full_node.rpc_client
662
+
663
+ await generate_funds(full_node_api, env.wallet_1)
664
+
665
+ signed_tx_amount = uint64(888000)
666
+ tx_coin_announcements = [
667
+ CreateCoinAnnouncement(
668
+ std_hash(b"\xca" + std_hash(b"message")),
669
+ std_hash(b"coin_id_1"),
670
+ ),
671
+ CreateCoinAnnouncement(
672
+ bytes(Program.to("a string")),
673
+ std_hash(b"coin_id_2"),
674
+ ),
675
+ ]
676
+ outputs = await create_tx_outputs(wallet_2, [(signed_tx_amount, None)])
677
+ tx_res: TransactionRecord = (
678
+ await client.create_signed_transactions(
679
+ outputs, tx_config=DEFAULT_TX_CONFIG, extra_conditions=(*tx_coin_announcements,)
680
+ )
681
+ ).signed_tx
682
+ assert_tx_amounts(tx_res, outputs, amount_fee=uint64(0), change_expected=True)
683
+ await assert_push_tx_error(client_node, tx_res)
684
+
685
+
686
+ @pytest.mark.anyio
687
+ async def test_create_signed_transaction_with_puzzle_announcement(wallet_rpc_environment: WalletRpcTestEnvironment):
688
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
689
+
690
+ wallet_2: Wallet = env.wallet_2.wallet
691
+ full_node_api: FullNodeSimulator = env.full_node.api
692
+ client: WalletRpcClient = env.wallet_1.rpc_client
693
+ client_node: FullNodeRpcClient = env.full_node.rpc_client
694
+
695
+ await generate_funds(full_node_api, env.wallet_1)
696
+
697
+ signed_tx_amount = uint64(888000)
698
+ tx_puzzle_announcements = [
699
+ CreatePuzzleAnnouncement(
700
+ std_hash(b"\xca" + std_hash(b"message")),
701
+ std_hash(b"puzzle_hash_1"),
702
+ ),
703
+ CreatePuzzleAnnouncement(
704
+ bytes(Program.to("a string")),
705
+ std_hash(b"puzzle_hash_2"),
706
+ ),
707
+ ]
708
+ outputs = await create_tx_outputs(wallet_2, [(signed_tx_amount, None)])
709
+ tx_res = (
710
+ await client.create_signed_transactions(
711
+ outputs, tx_config=DEFAULT_TX_CONFIG, extra_conditions=(*tx_puzzle_announcements,)
712
+ )
713
+ ).signed_tx
714
+ assert_tx_amounts(tx_res, outputs, amount_fee=uint64(0), change_expected=True)
715
+ await assert_push_tx_error(client_node, tx_res)
716
+
717
+
718
+ @pytest.mark.anyio
719
+ async def test_create_signed_transaction_with_excluded_coins(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
720
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
721
+ wallet_1: Wallet = env.wallet_1.wallet
722
+ wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
723
+ full_node_api: FullNodeSimulator = env.full_node.api
724
+ full_node_rpc: FullNodeRpcClient = env.full_node.rpc_client
725
+ await generate_funds(full_node_api, env.wallet_1)
726
+
727
+ async def it_does_not_include_the_excluded_coins() -> None:
728
+ selected_coins = await wallet_1_rpc.select_coins(
729
+ amount=250000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
730
+ )
731
+ assert len(selected_coins) == 1
732
+ outputs = await create_tx_outputs(wallet_1, [(uint64(250000000000), None)])
733
+
734
+ tx = (
735
+ await wallet_1_rpc.create_signed_transactions(
736
+ outputs,
737
+ DEFAULT_TX_CONFIG.override(
738
+ excluded_coin_ids=[c.name() for c in selected_coins],
739
+ ),
740
+ )
741
+ ).signed_tx
742
+
743
+ assert len(tx.removals) == 1
744
+ assert tx.removals[0] != selected_coins[0]
745
+ assert tx.removals[0].amount == uint64(1750000000000)
746
+ await assert_push_tx_error(full_node_rpc, tx)
747
+
748
+ async def it_throws_an_error_when_all_spendable_coins_are_excluded() -> None:
749
+ selected_coins = await wallet_1_rpc.select_coins(
750
+ amount=1750000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
751
+ )
752
+ assert len(selected_coins) == 1
753
+ outputs = await create_tx_outputs(wallet_1, [(uint64(1750000000000), None)])
754
+
755
+ with pytest.raises(ValueError):
756
+ await wallet_1_rpc.create_signed_transactions(
757
+ outputs,
758
+ DEFAULT_TX_CONFIG.override(
759
+ excluded_coin_ids=[c.name() for c in selected_coins],
760
+ ),
761
+ )
762
+
763
+ await it_does_not_include_the_excluded_coins()
764
+ await it_throws_an_error_when_all_spendable_coins_are_excluded()
765
+
766
+
767
+ @pytest.mark.anyio
768
+ async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnvironment):
769
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
770
+
771
+ wallet_1_node: WalletNode = env.wallet_1.node
772
+ wallet_2_node: WalletNode = env.wallet_2.node
773
+ wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
774
+ wallet_2_rpc: WalletRpcClient = env.wallet_2.rpc_client
775
+ wallet_1 = wallet_1_node.wallet_state_manager.main_wallet
776
+ wallet_2 = wallet_2_node.wallet_state_manager.main_wallet
777
+ full_node_api: FullNodeSimulator = env.full_node.api
778
+ wallet_2_api = WalletRpcApi(wallet_2_node)
779
+
780
+ generated_funds = await generate_funds(full_node_api, env.wallet_1, 1)
781
+ await generate_funds(full_node_api, env.wallet_2, 1)
782
+ wallet_1_puzhash = await wallet_1.get_new_puzzlehash()
783
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_1_node, timeout=20)
784
+ wallet_2_puzhash = await wallet_2.get_new_puzzlehash()
785
+ tx = (
786
+ await wallet_1_rpc.send_transaction(
787
+ wallet_id=1,
788
+ amount=uint64(500),
789
+ address=encode_puzzle_hash(wallet_2_puzhash, "txch"),
790
+ tx_config=DEFAULT_TX_CONFIG,
791
+ fee=uint64(0),
792
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
793
+ )
794
+ ).transaction
795
+ clawback_coin_id_1 = tx.additions[0].name()
796
+ assert tx.spend_bundle is not None
797
+ await farm_transaction(full_node_api, wallet_1_node, tx.spend_bundle)
798
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_2_node, timeout=20)
799
+ tx = (
800
+ await wallet_2_rpc.send_transaction(
801
+ wallet_id=1,
802
+ amount=uint64(500),
803
+ address=encode_puzzle_hash(wallet_1_puzhash, "txch"),
804
+ tx_config=DEFAULT_TX_CONFIG,
805
+ fee=uint64(0),
806
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
807
+ )
808
+ ).transaction
809
+ assert tx.spend_bundle is not None
810
+ clawback_coin_id_2 = tx.additions[0].name()
811
+ await farm_transaction(full_node_api, wallet_2_node, tx.spend_bundle)
812
+ await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_1_rpc, 1)
813
+ await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_2_rpc, 1)
814
+ await asyncio.sleep(10)
815
+ # Test missing coin_ids
816
+ has_exception = False
817
+ try:
818
+ await wallet_2_api.spend_clawback_coins({})
819
+ except ValueError:
820
+ has_exception = True
821
+ assert has_exception
822
+ # Test coin ID is not a Clawback coin
823
+ invalid_coin_id = tx.removals[0].name()
824
+ resp = await wallet_2_rpc.spend_clawback_coins([invalid_coin_id], 500)
825
+ assert resp["success"]
826
+ assert resp["transaction_ids"] == []
827
+ # Test unsupported wallet
828
+ coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_1)
829
+ assert coin_record is not None
830
+ await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
831
+ dataclasses.replace(coin_record, wallet_type=WalletType.CAT)
832
+ )
833
+ resp = await wallet_1_rpc.spend_clawback_coins([clawback_coin_id_1], 100)
834
+ assert resp["success"]
835
+ assert len(resp["transaction_ids"]) == 0
836
+ # Test missing metadata
837
+ await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(dataclasses.replace(coin_record, metadata=None))
838
+ resp = await wallet_1_rpc.spend_clawback_coins([clawback_coin_id_1], 100)
839
+ assert resp["success"]
840
+ assert len(resp["transaction_ids"]) == 0
841
+ # Test missing incoming tx
842
+ coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_2)
843
+ assert coin_record is not None
844
+ fake_coin = Coin(coin_record.coin.parent_coin_info, wallet_2_puzhash, coin_record.coin.amount)
845
+ await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
846
+ dataclasses.replace(coin_record, coin=fake_coin)
847
+ )
848
+ resp = await wallet_1_rpc.spend_clawback_coins([fake_coin.name()], 100)
849
+ assert resp["transaction_ids"] == []
850
+ # Test coin puzzle hash doesn't match the puzzle
851
+ farmed_tx = (await wallet_1.wallet_state_manager.tx_store.get_farming_rewards())[0]
852
+ await wallet_1.wallet_state_manager.tx_store.add_transaction_record(
853
+ dataclasses.replace(farmed_tx, name=fake_coin.name())
854
+ )
855
+ await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
856
+ dataclasses.replace(coin_record, coin=fake_coin)
857
+ )
858
+ resp = await wallet_1_rpc.spend_clawback_coins([fake_coin.name()], 100)
859
+ assert resp["transaction_ids"] == []
860
+ # Test claim spend
861
+ await wallet_2_rpc.set_auto_claim(
862
+ AutoClaimSettings(
863
+ enabled=False,
864
+ tx_fee=uint64(100),
865
+ min_amount=uint64(0),
866
+ batch_size=uint16(1),
867
+ )
868
+ )
869
+ resp = await wallet_2_rpc.spend_clawback_coins([clawback_coin_id_1, clawback_coin_id_2], 100)
870
+ assert resp["success"]
871
+ assert len(resp["transaction_ids"]) == 2
872
+ for _tx in resp["transactions"]:
873
+ clawback_tx = TransactionRecord.from_json_dict_convenience(_tx)
874
+ if clawback_tx.spend_bundle is not None:
875
+ await time_out_assert_not_none(
876
+ 10, full_node_api.full_node.mempool_manager.get_spendbundle, clawback_tx.spend_bundle.name()
877
+ )
878
+ await farm_transaction_block(full_node_api, wallet_2_node)
879
+ await time_out_assert(20, get_confirmed_balance, generated_funds + 300, wallet_2_rpc, 1)
880
+ # Test spent coin
881
+ resp = await wallet_2_rpc.spend_clawback_coins([clawback_coin_id_1], 500)
882
+ assert resp["success"]
883
+ assert resp["transaction_ids"] == []
884
+
885
+
886
+ @pytest.mark.anyio
887
+ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvironment):
888
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
889
+
890
+ wallet_2: Wallet = env.wallet_2.wallet
891
+ wallet_node: WalletNode = env.wallet_1.node
892
+ full_node_api: FullNodeSimulator = env.full_node.api
893
+ client: WalletRpcClient = env.wallet_1.rpc_client
894
+
895
+ generated_funds = await generate_funds(full_node_api, env.wallet_1)
896
+
897
+ removals = await client.select_coins(
898
+ 1750000000000, wallet_id=1, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
899
+ ) # we want a coin that won't be selected by default
900
+ outputs = await create_tx_outputs(wallet_2, [(uint64(1), ["memo_1"]), (uint64(2), ["memo_2"])])
901
+ amount_outputs = sum(output["amount"] for output in outputs)
902
+ amount_fee = uint64(amount_outputs + 1)
903
+
904
+ send_tx_res: TransactionRecord = (
905
+ await client.send_transaction_multi(
906
+ 1,
907
+ outputs,
908
+ DEFAULT_TX_CONFIG,
909
+ coins=removals,
910
+ fee=amount_fee,
911
+ )
912
+ ).transaction
913
+ spend_bundle = send_tx_res.spend_bundle
914
+ assert spend_bundle is not None
915
+ assert send_tx_res is not None
916
+
917
+ assert_tx_amounts(send_tx_res, outputs, amount_fee=amount_fee, change_expected=True)
918
+ assert send_tx_res.removals == removals
919
+
920
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
921
+
922
+ await time_out_assert(20, get_confirmed_balance, generated_funds - amount_outputs - amount_fee, client, 1)
923
+
924
+ # Checks that the memo can be retrieved
925
+ tx_confirmed = await client.get_transaction(send_tx_res.name)
926
+ assert tx_confirmed.confirmed
927
+ memos = tx_confirmed.get_memos()
928
+ assert len(memos) == len(outputs)
929
+ for output in outputs:
930
+ assert [output["memos"][0].encode()] in memos.values()
931
+ spend_bundle = send_tx_res.spend_bundle
932
+ assert spend_bundle is not None
933
+ for key in memos.keys():
934
+ assert key in [a.name() for a in spend_bundle.additions()]
935
+
936
+
937
+ @pytest.mark.anyio
938
+ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment):
939
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
940
+
941
+ wallet: Wallet = env.wallet_1.wallet
942
+ wallet_node: WalletNode = env.wallet_1.node
943
+ full_node_api: FullNodeSimulator = env.full_node.api
944
+ client: WalletRpcClient = env.wallet_1.rpc_client
945
+
946
+ await generate_funds(full_node_api, env.wallet_1, 5)
947
+
948
+ all_transactions = await client.get_transactions(1)
949
+ assert len(all_transactions) >= 10
950
+ # Test transaction pagination
951
+ some_transactions = await client.get_transactions(1, 0, 5)
952
+ some_transactions_2 = await client.get_transactions(1, 5, 10)
953
+ assert some_transactions == all_transactions[0:5]
954
+ assert some_transactions_2 == all_transactions[5:10]
955
+
956
+ # Testing sorts
957
+ # Test the default sort (CONFIRMED_AT_HEIGHT)
958
+ assert all_transactions == sorted(all_transactions, key=attrgetter("confirmed_at_height"))
959
+ all_transactions = await client.get_transactions(1, reverse=True)
960
+ assert all_transactions == sorted(all_transactions, key=attrgetter("confirmed_at_height"), reverse=True)
961
+
962
+ # Test RELEVANCE
963
+ puzhash = await wallet.get_new_puzzlehash()
964
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
965
+ await client.send_transaction(
966
+ 1, uint64(1), encode_puzzle_hash(puzhash, "txch"), DEFAULT_TX_CONFIG
967
+ ) # Create a pending tx
968
+
969
+ all_transactions = await client.get_transactions(1, sort_key=SortKey.RELEVANCE)
970
+ sorted_transactions = sorted(all_transactions, key=attrgetter("created_at_time"), reverse=True)
971
+ sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed_at_height"), reverse=True)
972
+ sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed"))
973
+ assert all_transactions == sorted_transactions
974
+
975
+ all_transactions = await client.get_transactions(1, sort_key=SortKey.RELEVANCE, reverse=True)
976
+ sorted_transactions = sorted(all_transactions, key=attrgetter("created_at_time"))
977
+ sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed_at_height"))
978
+ sorted_transactions = sorted(sorted_transactions, key=attrgetter("confirmed"), reverse=True)
979
+ assert all_transactions == sorted_transactions
980
+
981
+ # Test get_transactions to address
982
+ ph_by_addr = await wallet.get_new_puzzlehash()
983
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
984
+ await client.send_transaction(1, uint64(1), encode_puzzle_hash(ph_by_addr, "txch"), DEFAULT_TX_CONFIG)
985
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
986
+ tx_for_address = await client.get_transactions(1, to_address=encode_puzzle_hash(ph_by_addr, "txch"))
987
+ assert len(tx_for_address) == 1
988
+ assert tx_for_address[0].to_puzzle_hash == ph_by_addr
989
+
990
+ # Test type filter
991
+ all_transactions = await client.get_transactions(
992
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.COINBASE_REWARD])
993
+ )
994
+ assert len(all_transactions) == 5
995
+ assert all(transaction.type == TransactionType.COINBASE_REWARD for transaction in all_transactions)
996
+ # Test confirmed filter
997
+ all_transactions = await client.get_transactions(1, confirmed=True)
998
+ assert len(all_transactions) == 10
999
+ assert all(transaction.confirmed for transaction in all_transactions)
1000
+ all_transactions = await client.get_transactions(1, confirmed=False)
1001
+ assert len(all_transactions) == 2
1002
+ assert all(not transaction.confirmed for transaction in all_transactions)
1003
+
1004
+ # Test bypass broken txs
1005
+ await wallet.wallet_state_manager.tx_store.add_transaction_record(
1006
+ dataclasses.replace(all_transactions[0], type=uint32(TransactionType.INCOMING_CLAWBACK_SEND))
1007
+ )
1008
+ all_transactions = await client.get_transactions(
1009
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_CLAWBACK_SEND]), confirmed=False
1010
+ )
1011
+ assert len(all_transactions) == 1
1012
+
1013
+
1014
+ @pytest.mark.anyio
1015
+ async def test_get_transaction_count(wallet_rpc_environment: WalletRpcTestEnvironment):
1016
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1017
+
1018
+ full_node_api: FullNodeSimulator = env.full_node.api
1019
+ client: WalletRpcClient = env.wallet_1.rpc_client
1020
+
1021
+ await generate_funds(full_node_api, env.wallet_1)
1022
+
1023
+ all_transactions = await client.get_transactions(1)
1024
+ assert len(all_transactions) > 0
1025
+ transaction_count = await client.get_transaction_count(1)
1026
+ assert transaction_count == len(all_transactions)
1027
+ transaction_count = await client.get_transaction_count(1, confirmed=False)
1028
+ assert transaction_count == 0
1029
+ transaction_count = await client.get_transaction_count(
1030
+ 1, type_filter=TransactionTypeFilter.include([TransactionType.INCOMING_CLAWBACK_SEND])
1031
+ )
1032
+ assert transaction_count == 0
1033
+
1034
+
1035
+ @pytest.mark.anyio
1036
+ async def test_cat_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
1037
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1038
+
1039
+ wallet_node: WalletNode = env.wallet_1.node
1040
+
1041
+ client: WalletRpcClient = env.wallet_1.rpc_client
1042
+ client_2: WalletRpcClient = env.wallet_2.rpc_client
1043
+
1044
+ full_node_api: FullNodeSimulator = env.full_node.api
1045
+
1046
+ await generate_funds(full_node_api, env.wallet_1, 1)
1047
+ await generate_funds(full_node_api, env.wallet_2, 1)
1048
+
1049
+ # Test a deprecated path
1050
+ with pytest.raises(ValueError, match="dropped"):
1051
+ await client.fetch(
1052
+ "create_new_wallet",
1053
+ {
1054
+ "wallet_type": "cat_wallet",
1055
+ "mode": "new",
1056
+ },
1057
+ )
1058
+
1059
+ # Creates a CAT wallet with 100 mojos and a CAT with 20 mojos and fee=10
1060
+ await client.create_new_cat_and_wallet(uint64(100), fee=uint64(10), test=True)
1061
+ await time_out_assert(20, check_client_synced, True, client)
1062
+
1063
+ res = await client.create_new_cat_and_wallet(uint64(20), test=True)
1064
+ assert res["success"]
1065
+ cat_0_id = res["wallet_id"]
1066
+ asset_id = bytes32.fromhex(res["asset_id"])
1067
+ assert len(asset_id) > 0
1068
+
1069
+ await assert_wallet_types(client, {WalletType.STANDARD_WALLET: 1, WalletType.CAT: 2})
1070
+ await assert_wallet_types(client_2, {WalletType.STANDARD_WALLET: 1})
1071
+
1072
+ bal_0 = await client.get_wallet_balance(cat_0_id)
1073
+ assert bal_0["confirmed_wallet_balance"] == 0
1074
+ assert bal_0["pending_coin_removal_count"] == 1
1075
+ col = await client.get_cat_asset_id(cat_0_id)
1076
+ assert col == asset_id
1077
+ assert (await client.get_cat_name(cat_0_id)) == CATWallet.default_wallet_name_for_unknown_cat(asset_id.hex())
1078
+ await client.set_cat_name(cat_0_id, "My cat")
1079
+ assert (await client.get_cat_name(cat_0_id)) == "My cat"
1080
+ result = await client.cat_asset_id_to_name(col)
1081
+ assert result is not None
1082
+ wid, name = result
1083
+ assert wid == cat_0_id
1084
+ assert name == "My cat"
1085
+ result = await client.cat_asset_id_to_name(bytes32.zeros)
1086
+ assert result is None
1087
+ verified_asset_id = next(iter(DEFAULT_CATS.items()))[1]["asset_id"]
1088
+ result = await client.cat_asset_id_to_name(bytes32.from_hexstr(verified_asset_id))
1089
+ assert result is not None
1090
+ should_be_none, name = result
1091
+ assert should_be_none is None
1092
+ assert name == next(iter(DEFAULT_CATS.items()))[1]["name"]
1093
+
1094
+ # make sure spend is in mempool before farming tx block
1095
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 2)
1096
+ for i in range(5):
1097
+ if check_mempool_spend_count(full_node_api, 0):
1098
+ break
1099
+ await farm_transaction_block(full_node_api, wallet_node)
1100
+
1101
+ # check that we farmed the transaction
1102
+ assert check_mempool_spend_count(full_node_api, 0)
1103
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=5)
1104
+
1105
+ await time_out_assert(5, get_confirmed_balance, 20, client, cat_0_id)
1106
+ bal_0 = await client.get_wallet_balance(cat_0_id)
1107
+ assert bal_0["pending_coin_removal_count"] == 0
1108
+ assert bal_0["unspent_coin_count"] == 1
1109
+
1110
+ # Creates a second wallet with the same CAT
1111
+ res = await client_2.create_wallet_for_existing_cat(asset_id)
1112
+ assert res["success"]
1113
+ cat_1_id = res["wallet_id"]
1114
+ cat_1_asset_id = bytes.fromhex(res["asset_id"])
1115
+ assert cat_1_asset_id == asset_id
1116
+
1117
+ await assert_wallet_types(client, {WalletType.STANDARD_WALLET: 1, WalletType.CAT: 2})
1118
+ await assert_wallet_types(client_2, {WalletType.STANDARD_WALLET: 1, WalletType.CAT: 1})
1119
+
1120
+ await farm_transaction_block(full_node_api, wallet_node)
1121
+
1122
+ bal_1 = await client_2.get_wallet_balance(cat_1_id)
1123
+ assert bal_1["confirmed_wallet_balance"] == 0
1124
+
1125
+ addr_0 = await client.get_next_address(cat_0_id, False)
1126
+ addr_1 = await client_2.get_next_address(cat_1_id, False)
1127
+
1128
+ assert addr_0 != addr_1
1129
+
1130
+ # Test CAT spend without a fee
1131
+ with pytest.raises(ValueError):
1132
+ await client.cat_spend(
1133
+ cat_0_id,
1134
+ DEFAULT_TX_CONFIG.override(
1135
+ excluded_coin_amounts=[uint64(20)],
1136
+ excluded_coin_ids=[bytes32.zeros],
1137
+ ),
1138
+ uint64(4),
1139
+ addr_1,
1140
+ uint64(0),
1141
+ ["the cat memo"],
1142
+ )
1143
+ tx_res = await client.cat_spend(cat_0_id, DEFAULT_TX_CONFIG, uint64(4), addr_1, uint64(0), ["the cat memo"])
1144
+
1145
+ spend_bundle = tx_res.transaction.spend_bundle
1146
+ assert spend_bundle is not None
1147
+ assert uncurry_puzzle(spend_bundle.coin_spends[0].puzzle_reveal).mod == CAT_MOD
1148
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
1149
+
1150
+ await farm_transaction_block(full_node_api, wallet_node)
1151
+
1152
+ # Test CAT spend with a fee
1153
+ tx_res = await client.cat_spend(cat_0_id, DEFAULT_TX_CONFIG, uint64(1), addr_1, uint64(5_000_000), ["the cat memo"])
1154
+
1155
+ spend_bundle = tx_res.transaction.spend_bundle
1156
+ assert spend_bundle is not None
1157
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
1158
+
1159
+ # Test CAT spend with a fee and pre-specified removals / coins
1160
+ removals = await client.select_coins(
1161
+ amount=uint64(2), wallet_id=cat_0_id, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
1162
+ )
1163
+ tx_res = await client.cat_spend(
1164
+ cat_0_id, DEFAULT_TX_CONFIG, uint64(1), addr_1, uint64(5_000_000), ["the cat memo"], removals=removals
1165
+ )
1166
+
1167
+ spend_bundle = tx_res.transaction.spend_bundle
1168
+ assert spend_bundle is not None
1169
+ assert removals[0] in {removal for tx in tx_res.transactions for removal in tx.removals}
1170
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
1171
+
1172
+ # Test unacknowledged CAT
1173
+ await wallet_node.wallet_state_manager.interested_store.add_unacknowledged_token(
1174
+ asset_id, "Unknown", uint32(10000), bytes32(b"\00" * 32)
1175
+ )
1176
+ cats = await client.get_stray_cats()
1177
+ assert len(cats) == 1
1178
+
1179
+ await time_out_assert(20, get_confirmed_balance, 14, client, cat_0_id)
1180
+ await time_out_assert(20, get_confirmed_balance, 6, client_2, cat_1_id)
1181
+
1182
+ # Test CAT coin selection
1183
+ selected_coins = await client.select_coins(
1184
+ amount=1, wallet_id=cat_0_id, coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
1185
+ )
1186
+ assert len(selected_coins) > 0
1187
+
1188
+ # Test get_cat_list
1189
+ cat_list = (await client.get_cat_list()).cat_list
1190
+ assert len(DEFAULT_CATS) == len(cat_list)
1191
+ default_cats_set = {
1192
+ DefaultCAT(asset_id=bytes32.from_hexstr(cat["asset_id"]), name=cat["name"], symbol=cat["symbol"])
1193
+ for cat in DEFAULT_CATS.values()
1194
+ }
1195
+ assert default_cats_set == set(cat_list)
1196
+
1197
+
1198
+ @pytest.mark.anyio
1199
+ async def test_offer_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
1200
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1201
+
1202
+ wallet_node: WalletNode = env.wallet_1.node
1203
+ wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
1204
+ wallet_2_rpc: WalletRpcClient = env.wallet_2.rpc_client
1205
+ full_node_api: FullNodeSimulator = env.full_node.api
1206
+
1207
+ await generate_funds(full_node_api, env.wallet_1, 1)
1208
+ await generate_funds(full_node_api, env.wallet_2, 1)
1209
+
1210
+ # Creates a CAT wallet with 20 mojos
1211
+ res = await wallet_1_rpc.create_new_cat_and_wallet(uint64(20), test=True)
1212
+ assert res["success"]
1213
+ cat_wallet_id = res["wallet_id"]
1214
+ cat_asset_id = bytes32.fromhex(res["asset_id"])
1215
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1216
+ await farm_transaction_block(full_node_api, wallet_node)
1217
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=5)
1218
+
1219
+ await time_out_assert(5, get_confirmed_balance, 20, wallet_1_rpc, cat_wallet_id)
1220
+
1221
+ # Creates a wallet for the same CAT on wallet_2 and send 4 CAT from wallet_1 to it
1222
+ await wallet_2_rpc.create_wallet_for_existing_cat(cat_asset_id)
1223
+ wallet_2_address = await wallet_2_rpc.get_next_address(cat_wallet_id, False)
1224
+ adds = [{"puzzle_hash": decode_puzzle_hash(wallet_2_address), "amount": uint64(4), "memos": ["the cat memo"]}]
1225
+ tx_res = (
1226
+ await wallet_1_rpc.send_transaction_multi(
1227
+ cat_wallet_id, additions=adds, tx_config=DEFAULT_TX_CONFIG, fee=uint64(0)
1228
+ )
1229
+ ).transaction
1230
+ spend_bundle = tx_res.spend_bundle
1231
+ assert spend_bundle is not None
1232
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
1233
+ await time_out_assert(5, get_confirmed_balance, 4, wallet_2_rpc, cat_wallet_id)
1234
+ test_crs: list[CoinRecord] = await wallet_1_rpc.get_coin_records_by_names(
1235
+ [a.name() for a in spend_bundle.additions() if a.amount != 4]
1236
+ )
1237
+ for cr in test_crs:
1238
+ assert cr.coin in spend_bundle.additions()
1239
+ with pytest.raises(ValueError):
1240
+ await wallet_1_rpc.get_coin_records_by_names([a.name() for a in spend_bundle.additions() if a.amount == 4])
1241
+ # Create an offer of 5 chia for one CAT
1242
+ await wallet_1_rpc.create_offer_for_ids(
1243
+ {uint32(1): -5, cat_asset_id.hex(): 1}, DEFAULT_TX_CONFIG, validate_only=True
1244
+ )
1245
+ all_offers = await wallet_1_rpc.get_all_offers()
1246
+ assert len(all_offers) == 0
1247
+
1248
+ driver_dict: dict[str, Any] = {cat_asset_id.hex(): {"type": "CAT", "tail": "0x" + cat_asset_id.hex()}}
1249
+
1250
+ create_res = await wallet_1_rpc.create_offer_for_ids(
1251
+ {uint32(1): -5, cat_asset_id.hex(): 1},
1252
+ DEFAULT_TX_CONFIG,
1253
+ driver_dict=driver_dict,
1254
+ fee=uint64(1),
1255
+ )
1256
+ offer = create_res.offer
1257
+
1258
+ id, summary = await wallet_1_rpc.get_offer_summary(offer)
1259
+ assert id == offer.name()
1260
+ id, advanced_summary = await wallet_1_rpc.get_offer_summary(offer, advanced=True)
1261
+ assert id == offer.name()
1262
+ assert summary == {
1263
+ "offered": {"xch": 5},
1264
+ "requested": {cat_asset_id.hex(): 1},
1265
+ "infos": driver_dict,
1266
+ "fees": 1,
1267
+ "additions": [c.name().hex() for c in offer.additions()],
1268
+ "removals": [c.name().hex() for c in offer.removals()],
1269
+ "valid_times": {
1270
+ "max_height": None,
1271
+ "max_time": None,
1272
+ "min_height": None,
1273
+ "min_time": None,
1274
+ },
1275
+ }
1276
+ assert advanced_summary == summary
1277
+
1278
+ id, _valid = await wallet_1_rpc.check_offer_validity(offer)
1279
+ assert id == offer.name()
1280
+
1281
+ all_offers = await wallet_1_rpc.get_all_offers(file_contents=True)
1282
+ assert len(all_offers) == 1
1283
+ assert TradeStatus(all_offers[0].status) == TradeStatus.PENDING_ACCEPT
1284
+ assert all_offers[0].offer == bytes(offer)
1285
+
1286
+ offer_count = await wallet_1_rpc.get_offers_count()
1287
+ assert offer_count.total == 1
1288
+ assert offer_count.my_offers_count == 1
1289
+ assert offer_count.taken_offers_count == 0
1290
+
1291
+ trade_record = (await wallet_2_rpc.take_offer(offer, DEFAULT_TX_CONFIG, fee=uint64(1))).trade_record
1292
+ assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CONFIRM
1293
+
1294
+ await wallet_1_rpc.cancel_offer(offer.name(), DEFAULT_TX_CONFIG, secure=False)
1295
+
1296
+ trade_record = await wallet_1_rpc.get_offer(offer.name(), file_contents=True)
1297
+ assert trade_record.offer == bytes(offer)
1298
+ assert TradeStatus(trade_record.status) == TradeStatus.CANCELLED
1299
+
1300
+ await wallet_1_rpc.cancel_offer(offer.name(), DEFAULT_TX_CONFIG, fee=uint64(1), secure=True)
1301
+
1302
+ trade_record = await wallet_1_rpc.get_offer(offer.name())
1303
+ assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CANCEL
1304
+
1305
+ create_res = await wallet_1_rpc.create_offer_for_ids(
1306
+ {uint32(1): -5, cat_wallet_id: 1}, DEFAULT_TX_CONFIG, fee=uint64(1)
1307
+ )
1308
+ all_offers = await wallet_1_rpc.get_all_offers()
1309
+ assert len(all_offers) == 2
1310
+ offer_count = await wallet_1_rpc.get_offers_count()
1311
+ assert offer_count.total == 2
1312
+ assert offer_count.my_offers_count == 2
1313
+ assert offer_count.taken_offers_count == 0
1314
+ new_trade_record = create_res.trade_record
1315
+
1316
+ await farm_transaction_block(full_node_api, wallet_node)
1317
+
1318
+ async def is_trade_confirmed(client, trade) -> bool:
1319
+ trade_record = await client.get_offer(trade.name())
1320
+ return TradeStatus(trade_record.status) == TradeStatus.CONFIRMED
1321
+
1322
+ await time_out_assert(15, is_trade_confirmed, True, wallet_1_rpc, offer)
1323
+
1324
+ # Test trade sorting
1325
+ def only_ids(trades):
1326
+ return [t.trade_id for t in trades]
1327
+
1328
+ trade_record = await wallet_1_rpc.get_offer(offer.name())
1329
+ all_offers = await wallet_1_rpc.get_all_offers(include_completed=True) # confirmed at index descending
1330
+ assert len(all_offers) == 2
1331
+ assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
1332
+ all_offers = await wallet_1_rpc.get_all_offers(include_completed=True, reverse=True) # confirmed at index ascending
1333
+ assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
1334
+ all_offers = await wallet_1_rpc.get_all_offers(include_completed=True, sort_key="RELEVANCE") # most relevant
1335
+ assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
1336
+ all_offers = await wallet_1_rpc.get_all_offers(
1337
+ include_completed=True, sort_key="RELEVANCE", reverse=True
1338
+ ) # least relevant
1339
+ assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
1340
+ # Test pagination
1341
+ all_offers = await wallet_1_rpc.get_all_offers(include_completed=True, start=0, end=1)
1342
+ assert len(all_offers) == 1
1343
+ all_offers = await wallet_1_rpc.get_all_offers(include_completed=True, start=50)
1344
+ assert len(all_offers) == 0
1345
+ all_offers = await wallet_1_rpc.get_all_offers(include_completed=True, start=0, end=50)
1346
+ assert len(all_offers) == 2
1347
+
1348
+ ###
1349
+ # This is temporary code, delete it when we no longer care about incorrectly parsing old offers
1350
+ # There's also temp code in wallet_rpc_api.py
1351
+ with pytest.raises(ValueError, match="Old offer format is no longer supported"):
1352
+ await wallet_1_rpc.fetch(
1353
+ "get_offer_summary",
1354
+ {
1355
+ "offer": "offer1qqr83wcuu2rykcmqvpsxygqq0qthwpmsrsutadthxda7ppk8wemm74e88h2dh265k7fv7kdk2etmg99xpm0yu8ddl4rkhl73mflmfasl4h75w6lllup4t7urp0mstehm8cnmc6mdxn0rvdejdfpway2ccm6srenn6urvdmgvand96gat25z42f4u2sh7ad7upvhfty77v6ak76dmrdxrzdgn89mlr58ya6j77yax8095r2u2g826yg9jq4q6xzt4g6yveqnhg6r77lrt3weksdwcwz5ava4t5mtdem5syjejwg53q6t5lfd2t5p6dds9dylj7jxw2fmquugdnkvke5jckmsr8ne4akwha9hv9y24x6shezhaxqjegegprjp6h8hua2a24lntev22zkxdkhya5u7k6uhenv2jwwf8nddcs99707290u0yw7jv8w500yarnlew75keam9mwejmanardkdpk6awxj7ndl9ka35zfvydvfj646fuq7j6zv5uzl3czrw76psrnaudu2d65mtez7m9sz9xat52s87v6vmlpmknvju0u4wq5kklflwuamnaczl8vkne284ehyamaaxuzkcdvpjg3tlt7cxhy0r6fammc0arha65nxcv7kpxmra5zck7emrn7v4teuk6473eh7l39mqp5zafdmygm0tf0hp2ug20fhk7mlkmve4atg76xv9mw0xe2ped72mvkqall4hstp0a9jsxyyasz6dl7zmka2kwfx94w0knut43r4x447w3shmw5alldevrdu2gthelcjt8h6775p92ktlmlg846varj62rghj67e2hyhlauwkkv6nhnvt7wm6tt2kh2xw6kze0ttxsqplfct7mk4jvnykm0arw2juvnmkudgyerj59dn4ja8r5avud67zd7mr2cl54skynhs4twu2qgwrcdzcchhfee008e30yazzwu96h2uhaprejkrgns5w8nds244k3uyfhtmmzne29hmmdsvvlrtr02w0nc0thtkpywwmmxuqfc0tsssdflned" # noqa: E501
1356
+ },
1357
+ )
1358
+ with pytest.raises(ValueError, match="Old offer format is no longer supported"):
1359
+ await wallet_1_rpc.fetch(
1360
+ "check_offer_validity",
1361
+ {
1362
+ "offer": "offer1qqr83wcuu2rykcmqvpsxygqq0qthwpmsrsutadthxda7ppk8wemm74e88h2dh265k7fv7kdk2etmg99xpm0yu8ddl4rkhl73mflmfasl4h75w6lllup4t7urp0mstehm8cnmc6mdxn0rvdejdfpway2ccm6srenn6urvdmgvand96gat25z42f4u2sh7ad7upvhfty77v6ak76dmrdxrzdgn89mlr58ya6j77yax8095r2u2g826yg9jq4q6xzt4g6yveqnhg6r77lrt3weksdwcwz5ava4t5mtdem5syjejwg53q6t5lfd2t5p6dds9dylj7jxw2fmquugdnkvke5jckmsr8ne4akwha9hv9y24x6shezhaxqjegegprjp6h8hua2a24lntev22zkxdkhya5u7k6uhenv2jwwf8nddcs99707290u0yw7jv8w500yarnlew75keam9mwejmanardkdpk6awxj7ndl9ka35zfvydvfj646fuq7j6zv5uzl3czrw76psrnaudu2d65mtez7m9sz9xat52s87v6vmlpmknvju0u4wq5kklflwuamnaczl8vkne284ehyamaaxuzkcdvpjg3tlt7cxhy0r6fammc0arha65nxcv7kpxmra5zck7emrn7v4teuk6473eh7l39mqp5zafdmygm0tf0hp2ug20fhk7mlkmve4atg76xv9mw0xe2ped72mvkqall4hstp0a9jsxyyasz6dl7zmka2kwfx94w0knut43r4x447w3shmw5alldevrdu2gthelcjt8h6775p92ktlmlg846varj62rghj67e2hyhlauwkkv6nhnvt7wm6tt2kh2xw6kze0ttxsqplfct7mk4jvnykm0arw2juvnmkudgyerj59dn4ja8r5avud67zd7mr2cl54skynhs4twu2qgwrcdzcchhfee008e30yazzwu96h2uhaprejkrgns5w8nds244k3uyfhtmmzne29hmmdsvvlrtr02w0nc0thtkpywwmmxuqfc0tsssdflned" # noqa: E501
1363
+ },
1364
+ )
1365
+ with pytest.raises(ValueError, match="Old offer format is no longer supported"):
1366
+ await wallet_1_rpc.fetch(
1367
+ "take_offer",
1368
+ {
1369
+ "offer": "offer1qqr83wcuu2rykcmqvpsxygqq0qthwpmsrsutadthxda7ppk8wemm74e88h2dh265k7fv7kdk2etmg99xpm0yu8ddl4rkhl73mflmfasl4h75w6lllup4t7urp0mstehm8cnmc6mdxn0rvdejdfpway2ccm6srenn6urvdmgvand96gat25z42f4u2sh7ad7upvhfty77v6ak76dmrdxrzdgn89mlr58ya6j77yax8095r2u2g826yg9jq4q6xzt4g6yveqnhg6r77lrt3weksdwcwz5ava4t5mtdem5syjejwg53q6t5lfd2t5p6dds9dylj7jxw2fmquugdnkvke5jckmsr8ne4akwha9hv9y24x6shezhaxqjegegprjp6h8hua2a24lntev22zkxdkhya5u7k6uhenv2jwwf8nddcs99707290u0yw7jv8w500yarnlew75keam9mwejmanardkdpk6awxj7ndl9ka35zfvydvfj646fuq7j6zv5uzl3czrw76psrnaudu2d65mtez7m9sz9xat52s87v6vmlpmknvju0u4wq5kklflwuamnaczl8vkne284ehyamaaxuzkcdvpjg3tlt7cxhy0r6fammc0arha65nxcv7kpxmra5zck7emrn7v4teuk6473eh7l39mqp5zafdmygm0tf0hp2ug20fhk7mlkmve4atg76xv9mw0xe2ped72mvkqall4hstp0a9jsxyyasz6dl7zmka2kwfx94w0knut43r4x447w3shmw5alldevrdu2gthelcjt8h6775p92ktlmlg846varj62rghj67e2hyhlauwkkv6nhnvt7wm6tt2kh2xw6kze0ttxsqplfct7mk4jvnykm0arw2juvnmkudgyerj59dn4ja8r5avud67zd7mr2cl54skynhs4twu2qgwrcdzcchhfee008e30yazzwu96h2uhaprejkrgns5w8nds244k3uyfhtmmzne29hmmdsvvlrtr02w0nc0thtkpywwmmxuqfc0tsssdflned" # noqa: E501
1370
+ },
1371
+ )
1372
+ with pytest.raises(ValueError, match="Old offer format is no longer supported"):
1373
+ await wallet_1_rpc.fetch(
1374
+ "get_offer_summary",
1375
+ {
1376
+ "offer": "offer1qqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqx68z6sprqv0dvdkvr4rv8r8mwlw7mzuyht6gn74y8yx8ta952h2qqqqqqqqqqqqrls9lllq8ls9lllq8ls9l67lllsflczlllsflllqnlstlllqnll7zllxnlstq8lluz07zllszqgpq8lluz0llczlutl7tuqlllsfl6llllsflllqtljalllqnls9lllqnl30luqszqgplllqnll7qhl9tll7p8lqtll7p8lsgp8llllqnlcyptllllsfluzpdlllqyqszqgpq8lluz0lqdllllsfluzq9llllcyl7pq9lllluz0lqs9llll7p8lsg9llluqszqgpqyqszqgpqyqszq0llcylllsrlllllln63hlqtlnx08lluzqrlcpl7qukqhlllljplczllls8lc9lllsrlczlue0llcylup0llcyluxlllcylllshlmulllshle5lujgplllp0lhelllp0lhelllp0lnflevsrlsnq8llu9l7l8lp0ll7zllxnlcpqyqszq0lqyqszqgplllqy9cplcpsrll7qhlluplllezlllsnlllphlstq8ly2q0llcflllsmlctsrlj9q8llu2l79llluqcrluqsrll7q0lp0lstlctlutcplllq8ls3qyqluqcplllqtll7qllp0ll7q0lqtll7qllluylllczluh0llcylup0llcylufllqyqszq0lqstn7q0llcplup074hlluz07qhlluz0llczluflllcyla0lllcylutlllcyluhlllcyl7qmllllqnlcyqtllllsflcml7qgpqyqszqgpq8lluz0lqsp0llcpqyqszq0llcpluygpq8lqxq0llcplup0llcrlutlllcplup0llcrllljpluph7q0llcpsgqhllllq8ls3qyqluqcplllq8ls3qyqluqcpq8lqxq07p8lluz07p0ly7q0llcylll3plctlatcplmhszq0llllqtll7qllqhll7q0lqtll7qllluylllczllls8lllp8l3rl6csrll7q2el7qgplcpsrll7qvp37q0llcplup07fhlluz07qhlluz07r0lluz07zllluz0llcyl7qmnluzq9ucpluqszqgpqyqlllsrlczlaa0llcylup0llcyllls9lllq0ll7z0lz8l43q8lluql7p8ltrll7p8llup07ahlluz07qhlluz07yllluz0720lluz0llctlu607kuqlllsfletl7qgpqyqszqgpleeszq0llcplup0llcrlllsnlc3laugplllq8ls9lllq0ll7g8llup0llcrlllsnlllqyslllcdlu5cpq8lluql7qhlluplllcflllselefl7q07dyqlawgplllq8lszq0lszq07qvql7qgplcpszq0llcpp8ll7q0lpzqgplcpsrll7qgfsrlsrqyqluqcplllqnll7qhlluplllcflugl7kyqlllszk0lszq07qvqlllsflllqtljdlllqnls9lllqnlsmlllqnlshlllqnl30luqszqgpqyql7qgpqyqszqgplcpsrll7q0lqnlcplllqnlcplchszqgplcpsrll7qhllupl7p0lluql7p8lp8ll7qhl2mll7p8lqtll7p8lphll7p8lp0lcpqyqszqgplllqy9cplcpsrlshlmulllshle5lu5gplllp0lhelllp0lhelllp0lnflevsrlstq8llu9l7l8llup07vhlluz07qhlluz07pllluz0llctlu607dyql7qgpqyqsrll7zllxnlcpqyqszq0llczllls8lllqllstq8lluql7zllluqs9lllqtljalllqnls9lllqnlsnluqszqgplllqtljalllqnls9lllqnlsmluqszqgpq8lluql7zllluqsrlc9szq07qvqlllsflllqnlnplllqnl4lluqszq0llczlal0llcylup0llcylllsflllqnljllc9srll7p8ltllcyqtlszq0llcyllls9lexlllsflczlllsflctlllsflc9lllsrluqszqgpqyqlllsflchlllsfluphlll7p8lsgqhllllqnll7qhl9tll7p8lqtll7p8lsgz0llllqnll7qhlwmll7p8lqtll7p8lp8ll7p8lsg90llllqnll7zllxnljmq8lluz0790lszqgpqyqszq0llcyl7ppdlllszqgpqyqsrll7p8lsgzlllllqnlcyzlll7qgpqyqszqgpqyqszqgplczlad0llcylup0llcyla0lllcylualllcyllls9lllq0l30lllq8lsnledllls9le2lllsflczlllsfle8lllsflllqtlhdlllqnls9lllqnljnlllqnl40lllqnll7zllxnlcrwvqlllsfl6el7qgpqyqszqgplllqnlcrdllszqgpqyqszq0lqyqluqcplllqnl30lllqnlstlllqnlcyqhllllsflllqnll7p8l0rll7p8llu807h8llup07thlluz07qhlluz0llcyluhlllcyl7pqzlllszqgpluqszqgpq8lszqgplllqnll7p8lyrll7p8llu9llqdllaw0llczluh0llcylup0llcylllsflc4lllsflllzrlcyqtllll3rluzqt0l72uql7pq9luql7qgpq8lszqgpqyql7qgpq8lzwqgpluqszqgpqyqszqgpq8lqxqgplllqnll7qdqx7l0xc8wskqn8d5at9dfqmwyt5q675phnkk4zh4e2x9tklqa9fa0llcylllsrgqn55h9a7c7aq9zfj2tx6aa5268xz2r2ds5emgu9yut5hhkp96rrmll7p8lluql7qhlluql7qhlptll7p8lqtll7p8lq0lcpqyqsrll7p8lluqlllen8mll7qhllupl7p0lluql7p8lluz07r8lluz0llczlu00llcylup0llcyluyllqyqszq0lqyqsrll7qhlzmll7p8lqtll7p8lr8ll7p8llup07zhlluz07qhlluz07r0lszqgpq8lszqgpqyqsrlcpq8lqxq0llczllls8lc9lllsrlcylllsflcgluycplllqtl3dlllqnls9lllqnlsmlllqnlshluqszqgpqyqlllszzuqluqcplczllls8lllqllstq8lluql7zllluqs9lllqtl3alllqnls9lllqnlsnluqszqgplllqtl3alllqnls9lllqnlsmluqszqgpq8lluql7zllluqsrlc9szq07qvqluqcpq8lqxqgpqyqlll6pm3jc0w0dpj78zznpvxj057m22f2nk94gc3kus29jvxnefjjd4nklll6qehe6qve5g6r23z4txtrxjqhdg8npntzhw2w8yrkg7y50ksplt32lup0llaqvmuaqxv6ydp4g324n93nfqtk5rese43th98rjpmy0z28mgql4c4gpqyqsq00wsa2002kemp6v5g4avmmdc4edymhaj5vjzvnxuupgu00ufh83e8mt9q2autw93k0a55w5wf5mtdfdaxw9d3fk97dfqhtx8m2d32eqqqqqw3499peelczlllsrlczlllsrlczllls8lctlllsrlczllls8lllp8lstlllrhlshlllrmll7zllp0ll7qhlqmll7p8lqtll7p8lzllcpqyqszqgpqyqlllsrlczlutl7tuqlllsrlcgszq07qvqlllsrlcylllsflcylllsflc9lllsflllqtlsdlllqnls9lllqnl30luqszqgpluqszqgplllqtl30le0szqgplcpsrll7p8lluql7vhlqtll7qlllurl7pvqlllsrlctlllszqhllup07phlluz07qhlluz07z0lszqgpq8llup07phlluz07qhlluz07r0lszqgpqyqlllsrlctlllszq0lqkqgplcpsrlsrqyqlllsflllqxcgqwvaass7c74kdmgtgwq3v5kzcf7pdchnqjuw9yqd0agsgjr8tmua30nshgv7ddn8t3xehd0htnk5luqcpq8lsrll7q0lluellg96ufqk9maa268cn0r6xsre3fs33hcp384eu0uxj77w5fa0n8u008lsrq8lluellgyyddvdkw7jgeu9ugpwah0mk34v4un87qgnqaphe48qss0nmf637mlc2w3499pe4q8llu607qvqlllnelaqhyk2jzy6hxkmuzskhzpz5m6mwylj0h0akznfr3r7sw0e9n8ka2ycplll8ll6pp0j4c0pkvfpy06hd4gelhdvdp3798ghlx6m6eawkk5f4dcazw5cszq0lqyq5xlm42y5nv02th262u6tkmtmrq28nggx4mgvj35gewqav8wcn28jfgtphpthhwrs2pqys2s8zmwv6pur6s6vtyytar26hgp0tgcrc2xg0cxkqdfx3zyyckk769hp4p5dmvcfshc9a4j7feww6uvqc2mthvez7ttx" # noqa: E501
1377
+ },
1378
+ )
1379
+ with pytest.raises(ValueError, match="Old offer format is no longer supported"):
1380
+ await wallet_1_rpc.fetch(
1381
+ "check_offer_validity",
1382
+ {
1383
+ "offer": "offer1qqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqx68z6sprqv0dvdkvr4rv8r8mwlw7mzuyht6gn74y8yx8ta952h2qqqqqqqqqqqqrls9lllq8ls9lllq8ls9l67lllsflczlllsflllqnlstlllqnll7zllxnlstq8lluz07zllszqgpq8lluz0llczlutl7tuqlllsfl6llllsflllqtljalllqnls9lllqnl30luqszqgplllqnll7qhl9tll7p8lqtll7p8lsgp8llllqnlcyptllllsfluzpdlllqyqszqgpq8lluz0lqdllllsfluzq9llllcyl7pq9lllluz0lqs9llll7p8lsg9llluqszqgpqyqszqgpqyqszq0llcylllsrlllllln63hlqtlnx08lluzqrlcpl7qukqhlllljplczllls8lc9lllsrlczlue0llcylup0llcyluxlllcylllshlmulllshle5lujgplllp0lhelllp0lhelllp0lnflevsrlsnq8llu9l7l8lp0ll7zllxnlcpqyqszq0lqyqszqgplllqy9cplcpsrll7qhlluplllezlllsnlllphlstq8ly2q0llcflllsmlctsrlj9q8llu2l79llluqcrluqsrll7q0lp0lstlctlutcplllq8ls3qyqluqcplllqtll7qllp0ll7q0lqtll7qllluylllczluh0llcylup0llcylufllqyqszq0lqstn7q0llcplup074hlluz07qhlluz0llczluflllcyla0lllcylutlllcyluhlllcyl7qmllllqnlcyqtllllsflcml7qgpqyqszqgpq8lluz0lqsp0llcpqyqszq0llcpluygpq8lqxq0llcplup0llcrlutlllcplup0llcrllljpluph7q0llcpsgqhllllq8ls3qyqluqcplllq8ls3qyqluqcpq8lqxq07p8lluz07p0ly7q0llcylll3plctlatcplmhszq0llllqtll7qllqhll7q0lqtll7qllluylllczllls8lllp8l3rl6csrll7q2el7qgplcpsrll7qvp37q0llcplup07fhlluz07qhlluz07r0lluz07zllluz0llcyl7qmnluzq9ucpluqszqgpqyqlllsrlczlaa0llcylup0llcyllls9lllq0ll7z0lz8l43q8lluql7p8ltrll7p8llup07ahlluz07qhlluz07yllluz0720lluz0llctlu607kuqlllsfletl7qgpqyqszqgpleeszq0llcplup0llcrlllsnlc3laugplllq8ls9lllq0ll7g8llup0llcrlllsnlllqyslllcdlu5cpq8lluql7qhlluplllcflllselefl7q07dyqlawgplllq8lszq0lszq07qvql7qgplcpszq0llcpp8ll7q0lpzqgplcpsrll7qgfsrlsrqyqluqcplllqnll7qhlluplllcflugl7kyqlllszk0lszq07qvqlllsflllqtljdlllqnls9lllqnlsmlllqnlshlllqnl30luqszqgpqyql7qgpqyqszqgplcpsrll7q0lqnlcplllqnlcplchszqgplcpsrll7qhllupl7p0lluql7p8lp8ll7qhl2mll7p8lqtll7p8lphll7p8lp0lcpqyqszqgplllqy9cplcpsrlshlmulllshle5lu5gplllp0lhelllp0lhelllp0lnflevsrlstq8llu9l7l8llup07vhlluz07qhlluz07pllluz0llctlu607dyql7qgpqyqsrll7zllxnlcpqyqszq0llczllls8lllqllstq8lluql7zllluqs9lllqtljalllqnls9lllqnlsnluqszqgplllqtljalllqnls9lllqnlsmluqszqgpq8lluql7zllluqsrlc9szq07qvqlllsflllqnlnplllqnl4lluqszq0llczlal0llcylup0llcylllsflllqnljllc9srll7p8ltllcyqtlszq0llcyllls9lexlllsflczlllsflctlllsflc9lllsrluqszqgpqyqlllsflchlllsfluphlll7p8lsgqhllllqnll7qhl9tll7p8lqtll7p8lsgz0llllqnll7qhlwmll7p8lqtll7p8lp8ll7p8lsg90llllqnll7zllxnljmq8lluz0790lszqgpqyqszq0llcyl7ppdlllszqgpqyqsrll7p8lsgzlllllqnlcyzlll7qgpqyqszqgpqyqszqgplczlad0llcylup0llcyla0lllcylualllcyllls9lllq0l30lllq8lsnledllls9le2lllsflczlllsfle8lllsflllqtlhdlllqnls9lllqnljnlllqnl40lllqnll7zllxnlcrwvqlllsfl6el7qgpqyqszqgplllqnlcrdllszqgpqyqszq0lqyqluqcplllqnl30lllqnlstlllqnlcyqhllllsflllqnll7p8l0rll7p8llu807h8llup07thlluz07qhlluz0llcyluhlllcyl7pqzlllszqgpluqszqgpq8lszqgplllqnll7p8lyrll7p8llu9llqdllaw0llczluh0llcylup0llcylllsflc4lllsflllzrlcyqtllll3rluzqt0l72uql7pq9luql7qgpq8lszqgpqyql7qgpq8lzwqgpluqszqgpqyqszqgpq8lqxqgplllqnll7qdqx7l0xc8wskqn8d5at9dfqmwyt5q675phnkk4zh4e2x9tklqa9fa0llcylllsrgqn55h9a7c7aq9zfj2tx6aa5268xz2r2ds5emgu9yut5hhkp96rrmll7p8lluql7qhlluql7qhlptll7p8lqtll7p8lq0lcpqyqsrll7p8lluqlllen8mll7qhllupl7p0lluql7p8lluz07r8lluz0llczlu00llcylup0llcyluyllqyqszq0lqyqsrll7qhlzmll7p8lqtll7p8lr8ll7p8llup07zhlluz07qhlluz07r0lszqgpq8lszqgpqyqsrlcpq8lqxq0llczllls8lc9lllsrlcylllsflcgluycplllqtl3dlllqnls9lllqnlsmlllqnlshluqszqgpqyqlllszzuqluqcplczllls8lllqllstq8lluql7zllluqs9lllqtl3alllqnls9lllqnlsnluqszqgplllqtl3alllqnls9lllqnlsmluqszqgpq8lluql7zllluqsrlc9szq07qvqluqcpq8lqxqgpqyqlll6pm3jc0w0dpj78zznpvxj057m22f2nk94gc3kus29jvxnefjjd4nklll6qehe6qve5g6r23z4txtrxjqhdg8npntzhw2w8yrkg7y50ksplt32lup0llaqvmuaqxv6ydp4g324n93nfqtk5rese43th98rjpmy0z28mgql4c4gpqyqsq00wsa2002kemp6v5g4avmmdc4edymhaj5vjzvnxuupgu00ufh83e8mt9q2autw93k0a55w5wf5mtdfdaxw9d3fk97dfqhtx8m2d32eqqqqqw3499peelczlllsrlczlllsrlczllls8lctlllsrlczllls8lllp8lstlllrhlshlllrmll7zllp0ll7qhlqmll7p8lqtll7p8lzllcpqyqszqgpqyqlllsrlczlutl7tuqlllsrlcgszq07qvqlllsrlcylllsflcylllsflc9lllsflllqtlsdlllqnls9lllqnl30luqszqgpluqszqgplllqtl30le0szqgplcpsrll7p8lluql7vhlqtll7qlllurl7pvqlllsrlctlllszqhllup07phlluz07qhlluz07z0lszqgpq8llup07phlluz07qhlluz07r0lszqgpqyqlllsrlctlllszq0lqkqgplcpsrlsrqyqlllsflllqxcgqwvaass7c74kdmgtgwq3v5kzcf7pdchnqjuw9yqd0agsgjr8tmua30nshgv7ddn8t3xehd0htnk5luqcpq8lsrll7q0lluellg96ufqk9maa268cn0r6xsre3fs33hcp384eu0uxj77w5fa0n8u008lsrq8lluellgyyddvdkw7jgeu9ugpwah0mk34v4un87qgnqaphe48qss0nmf637mlc2w3499pe4q8llu607qvqlllnelaqhyk2jzy6hxkmuzskhzpz5m6mwylj0h0akznfr3r7sw0e9n8ka2ycplll8ll6pp0j4c0pkvfpy06hd4gelhdvdp3798ghlx6m6eawkk5f4dcazw5cszq0lqyq5xlm42y5nv02th262u6tkmtmrq28nggx4mgvj35gewqav8wcn28jfgtphpthhwrs2pqys2s8zmwv6pur6s6vtyytar26hgp0tgcrc2xg0cxkqdfx3zyyckk769hp4p5dmvcfshc9a4j7feww6uvqc2mthvez7ttx" # noqa: E501
1384
+ },
1385
+ )
1386
+ with pytest.raises(ValueError, match="Old offer format is no longer supported"):
1387
+ await wallet_1_rpc.fetch(
1388
+ "take_offer",
1389
+ {
1390
+ "offer": "offer1qqqqqqsqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqx68z6sprqv0dvdkvr4rv8r8mwlw7mzuyht6gn74y8yx8ta952h2qqqqqqqqqqqqrls9lllq8ls9lllq8ls9l67lllsflczlllsflllqnlstlllqnll7zllxnlstq8lluz07zllszqgpq8lluz0llczlutl7tuqlllsfl6llllsflllqtljalllqnls9lllqnl30luqszqgplllqnll7qhl9tll7p8lqtll7p8lsgp8llllqnlcyptllllsfluzpdlllqyqszqgpq8lluz0lqdllllsfluzq9llllcyl7pq9lllluz0lqs9llll7p8lsg9llluqszqgpqyqszqgpqyqszq0llcylllsrlllllln63hlqtlnx08lluzqrlcpl7qukqhlllljplczllls8lc9lllsrlczlue0llcylup0llcyluxlllcylllshlmulllshle5lujgplllp0lhelllp0lhelllp0lnflevsrlsnq8llu9l7l8lp0ll7zllxnlcpqyqszq0lqyqszqgplllqy9cplcpsrll7qhlluplllezlllsnlllphlstq8ly2q0llcflllsmlctsrlj9q8llu2l79llluqcrluqsrll7q0lp0lstlctlutcplllq8ls3qyqluqcplllqtll7qllp0ll7q0lqtll7qllluylllczluh0llcylup0llcylufllqyqszq0lqstn7q0llcplup074hlluz07qhlluz0llczluflllcyla0lllcylutlllcyluhlllcyl7qmllllqnlcyqtllllsflcml7qgpqyqszqgpq8lluz0lqsp0llcpqyqszq0llcpluygpq8lqxq0llcplup0llcrlutlllcplup0llcrllljpluph7q0llcpsgqhllllq8ls3qyqluqcplllq8ls3qyqluqcpq8lqxq07p8lluz07p0ly7q0llcylll3plctlatcplmhszq0llllqtll7qllqhll7q0lqtll7qllluylllczllls8lllp8l3rl6csrll7q2el7qgplcpsrll7qvp37q0llcplup07fhlluz07qhlluz07r0lluz07zllluz0llcyl7qmnluzq9ucpluqszqgpqyqlllsrlczlaa0llcylup0llcyllls9lllq0ll7z0lz8l43q8lluql7p8ltrll7p8llup07ahlluz07qhlluz07yllluz0720lluz0llctlu607kuqlllsfletl7qgpqyqszqgpleeszq0llcplup0llcrlllsnlc3laugplllq8ls9lllq0ll7g8llup0llcrlllsnlllqyslllcdlu5cpq8lluql7qhlluplllcflllselefl7q07dyqlawgplllq8lszq0lszq07qvql7qgplcpszq0llcpp8ll7q0lpzqgplcpsrll7qgfsrlsrqyqluqcplllqnll7qhlluplllcflugl7kyqlllszk0lszq07qvqlllsflllqtljdlllqnls9lllqnlsmlllqnlshlllqnl30luqszqgpqyql7qgpqyqszqgplcpsrll7q0lqnlcplllqnlcplchszqgplcpsrll7qhllupl7p0lluql7p8lp8ll7qhl2mll7p8lqtll7p8lphll7p8lp0lcpqyqszqgplllqy9cplcpsrlshlmulllshle5lu5gplllp0lhelllp0lhelllp0lnflevsrlstq8llu9l7l8llup07vhlluz07qhlluz07pllluz0llctlu607dyql7qgpqyqsrll7zllxnlcpqyqszq0llczllls8lllqllstq8lluql7zllluqs9lllqtljalllqnls9lllqnlsnluqszqgplllqtljalllqnls9lllqnlsmluqszqgpq8lluql7zllluqsrlc9szq07qvqlllsflllqnlnplllqnl4lluqszq0llczlal0llcylup0llcylllsflllqnljllc9srll7p8ltllcyqtlszq0llcyllls9lexlllsflczlllsflctlllsflc9lllsrluqszqgpqyqlllsflchlllsfluphlll7p8lsgqhllllqnll7qhl9tll7p8lqtll7p8lsgz0llllqnll7qhlwmll7p8lqtll7p8lp8ll7p8lsg90llllqnll7zllxnljmq8lluz0790lszqgpqyqszq0llcyl7ppdlllszqgpqyqsrll7p8lsgzlllllqnlcyzlll7qgpqyqszqgpqyqszqgplczlad0llcylup0llcyla0lllcylualllcyllls9lllq0l30lllq8lsnledllls9le2lllsflczlllsfle8lllsflllqtlhdlllqnls9lllqnljnlllqnl40lllqnll7zllxnlcrwvqlllsfl6el7qgpqyqszqgplllqnlcrdllszqgpqyqszq0lqyqluqcplllqnl30lllqnlstlllqnlcyqhllllsflllqnll7p8l0rll7p8llu807h8llup07thlluz07qhlluz0llcyluhlllcyl7pqzlllszqgpluqszqgpq8lszqgplllqnll7p8lyrll7p8llu9llqdllaw0llczluh0llcylup0llcylllsflc4lllsflllzrlcyqtllll3rluzqt0l72uql7pq9luql7qgpq8lszqgpqyql7qgpq8lzwqgpluqszqgpqyqszqgpq8lqxqgplllqnll7qdqx7l0xc8wskqn8d5at9dfqmwyt5q675phnkk4zh4e2x9tklqa9fa0llcylllsrgqn55h9a7c7aq9zfj2tx6aa5268xz2r2ds5emgu9yut5hhkp96rrmll7p8lluql7qhlluql7qhlptll7p8lqtll7p8lq0lcpqyqsrll7p8lluqlllen8mll7qhllupl7p0lluql7p8lluz07r8lluz0llczlu00llcylup0llcyluyllqyqszq0lqyqsrll7qhlzmll7p8lqtll7p8lr8ll7p8llup07zhlluz07qhlluz07r0lszqgpq8lszqgpqyqsrlcpq8lqxq0llczllls8lc9lllsrlcylllsflcgluycplllqtl3dlllqnls9lllqnlsmlllqnlshluqszqgpqyqlllszzuqluqcplczllls8lllqllstq8lluql7zllluqs9lllqtl3alllqnls9lllqnlsnluqszqgplllqtl3alllqnls9lllqnlsmluqszqgpq8lluql7zllluqsrlc9szq07qvqluqcpq8lqxqgpqyqlll6pm3jc0w0dpj78zznpvxj057m22f2nk94gc3kus29jvxnefjjd4nklll6qehe6qve5g6r23z4txtrxjqhdg8npntzhw2w8yrkg7y50ksplt32lup0llaqvmuaqxv6ydp4g324n93nfqtk5rese43th98rjpmy0z28mgql4c4gpqyqsq00wsa2002kemp6v5g4avmmdc4edymhaj5vjzvnxuupgu00ufh83e8mt9q2autw93k0a55w5wf5mtdfdaxw9d3fk97dfqhtx8m2d32eqqqqqw3499peelczlllsrlczlllsrlczllls8lctlllsrlczllls8lllp8lstlllrhlshlllrmll7zllp0ll7qhlqmll7p8lqtll7p8lzllcpqyqszqgpqyqlllsrlczlutl7tuqlllsrlcgszq07qvqlllsrlcylllsflcylllsflc9lllsflllqtlsdlllqnls9lllqnl30luqszqgpluqszqgplllqtl30le0szqgplcpsrll7p8lluql7vhlqtll7qlllurl7pvqlllsrlctlllszqhllup07phlluz07qhlluz07z0lszqgpq8llup07phlluz07qhlluz07r0lszqgpqyqlllsrlctlllszq0lqkqgplcpsrlsrqyqlllsflllqxcgqwvaass7c74kdmgtgwq3v5kzcf7pdchnqjuw9yqd0agsgjr8tmua30nshgv7ddn8t3xehd0htnk5luqcpq8lsrll7q0lluellg96ufqk9maa268cn0r6xsre3fs33hcp384eu0uxj77w5fa0n8u008lsrq8lluellgyyddvdkw7jgeu9ugpwah0mk34v4un87qgnqaphe48qss0nmf637mlc2w3499pe4q8llu607qvqlllnelaqhyk2jzy6hxkmuzskhzpz5m6mwylj0h0akznfr3r7sw0e9n8ka2ycplll8ll6pp0j4c0pkvfpy06hd4gelhdvdp3798ghlx6m6eawkk5f4dcazw5cszq0lqyq5xlm42y5nv02th262u6tkmtmrq28nggx4mgvj35gewqav8wcn28jfgtphpthhwrs2pqys2s8zmwv6pur6s6vtyytar26hgp0tgcrc2xg0cxkqdfx3zyyckk769hp4p5dmvcfshc9a4j7feww6uvqc2mthvez7ttx" # noqa: E501
1391
+ },
1392
+ )
1393
+ ###
1394
+
1395
+ await wallet_1_rpc.create_offer_for_ids(
1396
+ {uint32(1): -5, cat_asset_id.hex(): 1},
1397
+ DEFAULT_TX_CONFIG,
1398
+ driver_dict=driver_dict,
1399
+ )
1400
+ assert len([o for o in await wallet_1_rpc.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 2
1401
+ await wallet_1_rpc.cancel_offers(DEFAULT_TX_CONFIG, batch_size=1)
1402
+ assert len([o for o in await wallet_1_rpc.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 0
1403
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 2)
1404
+
1405
+ await farm_transaction_block(full_node_api, wallet_node)
1406
+
1407
+ await wallet_1_rpc.create_offer_for_ids(
1408
+ {uint32(1): -5, cat_asset_id.hex(): 1},
1409
+ DEFAULT_TX_CONFIG,
1410
+ driver_dict=driver_dict,
1411
+ )
1412
+ await wallet_1_rpc.create_offer_for_ids(
1413
+ {uint32(1): 5, cat_asset_id.hex(): -1},
1414
+ DEFAULT_TX_CONFIG,
1415
+ driver_dict=driver_dict,
1416
+ )
1417
+ assert len([o for o in await wallet_1_rpc.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 2
1418
+ await wallet_1_rpc.cancel_offers(DEFAULT_TX_CONFIG, cancel_all=True)
1419
+ assert len([o for o in await wallet_1_rpc.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 0
1420
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1421
+ await farm_transaction_block(full_node_api, wallet_node)
1422
+
1423
+ await wallet_1_rpc.create_offer_for_ids(
1424
+ {uint32(1): 5, cat_asset_id.hex(): -1},
1425
+ DEFAULT_TX_CONFIG,
1426
+ driver_dict=driver_dict,
1427
+ )
1428
+ assert len([o for o in await wallet_1_rpc.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 1
1429
+ await wallet_1_rpc.cancel_offers(DEFAULT_TX_CONFIG, asset_id=bytes32.zeros)
1430
+ assert len([o for o in await wallet_1_rpc.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 1
1431
+ await wallet_1_rpc.cancel_offers(DEFAULT_TX_CONFIG, asset_id=cat_asset_id)
1432
+ assert len([o for o in await wallet_1_rpc.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 0
1433
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1434
+
1435
+ with pytest.raises(ValueError, match="not currently supported"):
1436
+ await wallet_1_rpc.create_offer_for_ids(
1437
+ {uint32(1): -5, cat_asset_id.hex(): 1},
1438
+ DEFAULT_TX_CONFIG,
1439
+ driver_dict=driver_dict,
1440
+ timelock_info=ConditionValidTimes(min_secs_since_created=uint64(1)),
1441
+ )
1442
+
1443
+
1444
+ @pytest.mark.anyio
1445
+ async def test_get_coin_records_by_names(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
1446
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1447
+ wallet_node: WalletNode = env.wallet_1.node
1448
+ client: WalletRpcClient = env.wallet_1.rpc_client
1449
+ store = wallet_node.wallet_state_manager.coin_store
1450
+ full_node_api = env.full_node.api
1451
+ # Generate some funds
1452
+ generated_funds = await generate_funds(full_node_api, env.wallet_1, 5)
1453
+ address = encode_puzzle_hash(await env.wallet_1.wallet.get_new_puzzlehash(), "txch")
1454
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
1455
+
1456
+ # Spend half of it back to the same wallet get some spent coins in the wallet
1457
+ tx = (await client.send_transaction(1, uint64(generated_funds / 2), address, DEFAULT_TX_CONFIG)).transaction
1458
+ assert tx.spend_bundle is not None
1459
+ await time_out_assert(20, tx_in_mempool, True, client, tx.name)
1460
+ await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
1461
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=5)
1462
+ # Prepare some records and parameters first
1463
+ result = await store.get_coin_records()
1464
+ coins = {record.coin for record in result.records}
1465
+ coins_unspent = {record.coin for record in result.records if not record.spent}
1466
+ coin_ids = [coin.name() for coin in coins]
1467
+ coin_ids_unspent = [coin.name() for coin in coins_unspent]
1468
+ assert len(coin_ids) > 0
1469
+ assert len(coin_ids_unspent) > 0
1470
+ # Do some queries to trigger all parameters
1471
+ # 1. Empty coin_ids
1472
+ assert await client.get_coin_records_by_names([]) == []
1473
+ # 2. All coins
1474
+ rpc_result = await client.get_coin_records_by_names(coin_ids + coin_ids_unspent)
1475
+ assert {record.coin for record in rpc_result} == {*coins, *coins_unspent}
1476
+ # 3. All spent coins
1477
+ rpc_result = await client.get_coin_records_by_names(coin_ids, include_spent_coins=True)
1478
+ assert {record.coin for record in rpc_result} == coins
1479
+ # 4. All unspent coins
1480
+ rpc_result = await client.get_coin_records_by_names(coin_ids_unspent, include_spent_coins=False)
1481
+ assert {record.coin for record in rpc_result} == coins_unspent
1482
+ # 5. Filter start/end height
1483
+ filter_records = result.records[:10]
1484
+ assert len(filter_records) == 10
1485
+ filter_coin_ids = [record.name() for record in filter_records]
1486
+ filter_coins = {record.coin for record in filter_records}
1487
+ min_height = min(record.confirmed_block_height for record in filter_records)
1488
+ max_height = max(record.confirmed_block_height for record in filter_records)
1489
+ assert min_height != max_height
1490
+ rpc_result = await client.get_coin_records_by_names(filter_coin_ids, start_height=min_height, end_height=max_height)
1491
+ assert {record.coin for record in rpc_result} == filter_coins
1492
+ # 8. Test the failure case
1493
+ with pytest.raises(ValueError, match="not found"):
1494
+ await client.get_coin_records_by_names(coin_ids, include_spent_coins=False)
1495
+
1496
+
1497
+ @pytest.mark.anyio
1498
+ async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
1499
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1500
+
1501
+ wallet_1: Wallet = env.wallet_1.wallet
1502
+ wallet_2: Wallet = env.wallet_2.wallet
1503
+ wallet_1_node: WalletNode = env.wallet_1.node
1504
+ wallet_2_node: WalletNode = env.wallet_2.node
1505
+ wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
1506
+ wallet_2_rpc: WalletRpcClient = env.wallet_2.rpc_client
1507
+ full_node_api: FullNodeSimulator = env.full_node.api
1508
+ wallet_1_id = wallet_1.id()
1509
+
1510
+ await generate_funds(env.full_node.api, env.wallet_1, 5)
1511
+
1512
+ # Create a DID wallet
1513
+ res = await wallet_1_rpc.create_new_did_wallet(amount=1, tx_config=DEFAULT_TX_CONFIG, name="Profile 1")
1514
+ assert res["success"]
1515
+ did_wallet_id_0 = res["wallet_id"]
1516
+ did_id_0 = res["my_did"]
1517
+
1518
+ # Get wallet name
1519
+ res = await wallet_1_rpc.did_get_wallet_name(did_wallet_id_0)
1520
+ assert res["success"]
1521
+ assert res["name"] == "Profile 1"
1522
+ nft_wallet: WalletProtocol = wallet_1_node.wallet_state_manager.wallets[did_wallet_id_0 + 1]
1523
+ assert isinstance(nft_wallet, NFTWallet)
1524
+ assert nft_wallet.get_name() == "Profile 1 NFT Wallet"
1525
+
1526
+ # Set wallet name
1527
+ new_wallet_name = "test name"
1528
+ res = await wallet_1_rpc.did_set_wallet_name(did_wallet_id_0, new_wallet_name)
1529
+ assert res["success"]
1530
+ res = await wallet_1_rpc.did_get_wallet_name(did_wallet_id_0)
1531
+ assert res["success"]
1532
+ assert res["name"] == new_wallet_name
1533
+ with pytest.raises(ValueError, match="wallet id 1 is of type Wallet but type DIDWallet is required"):
1534
+ await wallet_1_rpc.did_set_wallet_name(wallet_1_id, new_wallet_name)
1535
+
1536
+ # Check DID ID
1537
+ res = await wallet_1_rpc.get_did_id(did_wallet_id_0)
1538
+ assert res["success"]
1539
+ assert did_id_0 == res["my_did"]
1540
+ # Create backup file
1541
+ res = await wallet_1_rpc.create_did_backup_file(did_wallet_id_0, "backup.did")
1542
+ assert res["success"]
1543
+
1544
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1545
+ await farm_transaction_block(full_node_api, wallet_1_node)
1546
+ # Update recovery list
1547
+ update_res = await wallet_1_rpc.update_did_recovery_list(did_wallet_id_0, [did_id_0], 1, DEFAULT_TX_CONFIG)
1548
+ assert len(update_res.transactions) > 0
1549
+ res = await wallet_1_rpc.get_did_recovery_list(did_wallet_id_0)
1550
+ assert res["num_required"] == 1
1551
+ assert res["recovery_list"][0] == did_id_0
1552
+
1553
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1554
+ await farm_transaction_block(full_node_api, wallet_1_node)
1555
+
1556
+ # Update metadata
1557
+ with pytest.raises(ValueError, match="wallet id 1 is of type Wallet but type DIDWallet is required"):
1558
+ await wallet_1_rpc.update_did_metadata(wallet_1_id, {"Twitter": "Https://test"}, DEFAULT_TX_CONFIG)
1559
+ await wallet_1_rpc.update_did_metadata(did_wallet_id_0, {"Twitter": "Https://test"}, DEFAULT_TX_CONFIG)
1560
+
1561
+ res = await wallet_1_rpc.get_did_metadata(did_wallet_id_0)
1562
+ assert res["metadata"]["Twitter"] == "Https://test"
1563
+
1564
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1565
+ await farm_transaction_block(full_node_api, wallet_1_node)
1566
+
1567
+ # Transfer DID
1568
+ addr = encode_puzzle_hash(await wallet_2.get_new_puzzlehash(), "txch")
1569
+ await wallet_1_rpc.did_transfer_did(did_wallet_id_0, addr, 0, True, DEFAULT_TX_CONFIG)
1570
+
1571
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1572
+ await farm_transaction_block(full_node_api, wallet_1_node)
1573
+
1574
+ async def num_wallets() -> int:
1575
+ return len(await wallet_2_node.wallet_state_manager.get_all_wallet_info_entries())
1576
+
1577
+ await time_out_assert(30, num_wallets, 2)
1578
+
1579
+ did_wallets = list(
1580
+ filter(
1581
+ lambda w: (w.type == WalletType.DECENTRALIZED_ID),
1582
+ await wallet_2_node.wallet_state_manager.get_all_wallet_info_entries(),
1583
+ )
1584
+ )
1585
+ did_wallet_2: WalletProtocol = wallet_2_node.wallet_state_manager.wallets[did_wallets[0].id]
1586
+ assert isinstance(did_wallet_2, DIDWallet)
1587
+ assert (
1588
+ encode_puzzle_hash(bytes32.from_hexstr(did_wallet_2.get_my_DID()), AddressType.DID.hrp(wallet_2_node.config))
1589
+ == did_id_0
1590
+ )
1591
+ metadata = json.loads(did_wallet_2.did_info.metadata)
1592
+ assert metadata["Twitter"] == "Https://test"
1593
+
1594
+ last_did_coin = await did_wallet_2.get_coin()
1595
+ await wallet_2_rpc.did_message_spend(did_wallet_2.id(), DEFAULT_TX_CONFIG, push=True)
1596
+ await wallet_2_node.wallet_state_manager.add_interested_coin_ids([last_did_coin.name()])
1597
+
1598
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1599
+ await farm_transaction_block(full_node_api, wallet_2_node)
1600
+
1601
+ next_did_coin = await did_wallet_2.get_coin()
1602
+ assert next_did_coin.parent_coin_info == last_did_coin.name()
1603
+ last_did_coin = next_did_coin
1604
+
1605
+ await wallet_2_rpc.did_message_spend(did_wallet_2.id(), DEFAULT_TX_CONFIG.override(reuse_puzhash=True), push=True)
1606
+ await wallet_2_node.wallet_state_manager.add_interested_coin_ids([last_did_coin.name()])
1607
+
1608
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1609
+ await farm_transaction_block(full_node_api, wallet_2_node)
1610
+
1611
+ next_did_coin = await did_wallet_2.get_coin()
1612
+ assert next_did_coin.parent_coin_info == last_did_coin.name()
1613
+ assert next_did_coin.puzzle_hash == last_did_coin.puzzle_hash
1614
+
1615
+ # Test did_get_pubkey
1616
+ pubkey_res = await wallet_2_rpc.get_did_pubkey(DIDGetPubkey(did_wallet_2.id()))
1617
+ assert isinstance(pubkey_res.pubkey, G1Element)
1618
+
1619
+
1620
+ @pytest.mark.anyio
1621
+ async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
1622
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1623
+ wallet_1_node: WalletNode = env.wallet_1.node
1624
+ wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
1625
+ wallet_2: Wallet = env.wallet_2.wallet
1626
+ wallet_2_node: WalletNode = env.wallet_2.node
1627
+ wallet_2_rpc: WalletRpcClient = env.wallet_2.rpc_client
1628
+ full_node_api: FullNodeSimulator = env.full_node.api
1629
+
1630
+ await generate_funds(env.full_node.api, env.wallet_1, 5)
1631
+
1632
+ res = await wallet_1_rpc.create_new_nft_wallet(None)
1633
+ nft_wallet_id = res["wallet_id"]
1634
+ mint_res = await wallet_1_rpc.mint_nft(
1635
+ nft_wallet_id,
1636
+ None,
1637
+ None,
1638
+ "0xD4584AD463139FA8C0D9F68F4B59F185",
1639
+ ["https://www.chia.net/img/branding/chia-logo.svg"],
1640
+ DEFAULT_TX_CONFIG,
1641
+ )
1642
+
1643
+ spend_bundle = mint_res.spend_bundle
1644
+
1645
+ await farm_transaction(full_node_api, wallet_1_node, spend_bundle)
1646
+
1647
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_1_node, timeout=15)
1648
+
1649
+ nft_wallet: WalletProtocol = wallet_1_node.wallet_state_manager.wallets[nft_wallet_id]
1650
+ assert isinstance(nft_wallet, NFTWallet)
1651
+
1652
+ async def have_nfts():
1653
+ return await nft_wallet.get_nft_count() > 0
1654
+
1655
+ await time_out_assert(15, have_nfts, True)
1656
+
1657
+ # Test with the hex version of nft_id
1658
+ nft_id = (await nft_wallet.get_current_nfts())[0].coin.name().hex()
1659
+ nft_info = (await wallet_1_rpc.get_nft_info(nft_id))["nft_info"]
1660
+ assert nft_info["nft_coin_id"][2:] == (await nft_wallet.get_current_nfts())[0].coin.name().hex()
1661
+ # Test with the bech32m version of nft_id
1662
+ hmr_nft_id = encode_puzzle_hash(
1663
+ (await nft_wallet.get_current_nfts())[0].coin.name(), AddressType.NFT.hrp(wallet_1_node.config)
1664
+ )
1665
+ nft_info = (await wallet_1_rpc.get_nft_info(hmr_nft_id))["nft_info"]
1666
+ assert nft_info["nft_coin_id"][2:] == (await nft_wallet.get_current_nfts())[0].coin.name().hex()
1667
+
1668
+ addr = encode_puzzle_hash(await wallet_2.get_new_puzzlehash(), "txch")
1669
+ await wallet_1_rpc.transfer_nft(nft_wallet_id, nft_id, addr, 0, DEFAULT_TX_CONFIG)
1670
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
1671
+ await farm_transaction_block(full_node_api, wallet_1_node)
1672
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 0)
1673
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_1_node, timeout=5)
1674
+
1675
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_2_node, timeout=5)
1676
+
1677
+ nft_wallet_id_1 = (
1678
+ await wallet_2_node.wallet_state_manager.get_all_wallet_info_entries(wallet_type=WalletType.NFT)
1679
+ )[0].id
1680
+ nft_wallet_1: WalletProtocol = wallet_2_node.wallet_state_manager.wallets[nft_wallet_id_1]
1681
+ assert isinstance(nft_wallet_1, NFTWallet)
1682
+ nft_info_1 = (await wallet_1_rpc.get_nft_info(nft_id, False))["nft_info"]
1683
+ assert nft_info_1 == nft_info
1684
+ nft_info_1 = (await wallet_1_rpc.get_nft_info(nft_id))["nft_info"]
1685
+ assert nft_info_1["nft_coin_id"][2:] == (await nft_wallet_1.get_current_nfts())[0].coin.name().hex()
1686
+ # Cross-check NFT
1687
+ nft_info_2 = (await wallet_2_rpc.list_nfts(nft_wallet_id_1))["nft_list"][0]
1688
+ assert nft_info_1 == nft_info_2
1689
+
1690
+ # Test royalty endpoint
1691
+ royalty_summary = await wallet_1_rpc.nft_calculate_royalties(
1692
+ {
1693
+ "my asset": ("my address", uint16(10000)),
1694
+ },
1695
+ {
1696
+ None: uint64(10000),
1697
+ },
1698
+ )
1699
+ assert royalty_summary == {
1700
+ "my asset": [
1701
+ {
1702
+ "asset": None,
1703
+ "address": "my address",
1704
+ "amount": 10000,
1705
+ }
1706
+ ],
1707
+ }
1708
+
1709
+
1710
+ async def _check_delete_key(
1711
+ client: WalletRpcClient, wallet_node: WalletNode, farmer_fp: int, pool_fp: int, observer: bool = False
1712
+ ) -> None:
1713
+ # Add in reward addresses into farmer and pool for testing delete key checks
1714
+ # set farmer to first private key
1715
+ create_sk = master_sk_to_wallet_sk_unhardened if observer else master_sk_to_wallet_sk
1716
+
1717
+ sk = await wallet_node.get_key_for_fingerprint(farmer_fp, private=True)
1718
+ assert sk is not None
1719
+ farmer_ph = create_puzzlehash_for_pk(create_sk(sk, uint32(0)).get_g1())
1720
+
1721
+ sk = await wallet_node.get_key_for_fingerprint(pool_fp, private=True)
1722
+ assert sk is not None
1723
+ pool_ph = create_puzzlehash_for_pk(create_sk(sk, uint32(0)).get_g1())
1724
+
1725
+ with lock_and_load_config(wallet_node.root_path, "config.yaml") as test_config:
1726
+ test_config["farmer"]["xch_target_address"] = encode_puzzle_hash(farmer_ph, "txch")
1727
+ test_config["pool"]["xch_target_address"] = encode_puzzle_hash(pool_ph, "txch")
1728
+ save_config(wallet_node.root_path, "config.yaml", test_config)
1729
+
1730
+ # Check farmer_fp key
1731
+ resp = await client.check_delete_key(CheckDeleteKey(uint32(farmer_fp)))
1732
+ assert resp.fingerprint == farmer_fp
1733
+ assert resp.used_for_farmer_rewards is True
1734
+ assert resp.used_for_pool_rewards is False
1735
+
1736
+ # Check pool_fp key
1737
+ resp = await client.check_delete_key(CheckDeleteKey(uint32(pool_fp)))
1738
+ assert resp.fingerprint == pool_fp
1739
+ assert resp.used_for_farmer_rewards is False
1740
+ assert resp.used_for_pool_rewards is True
1741
+
1742
+ # Check unknown key
1743
+ resp = await client.check_delete_key(CheckDeleteKey(uint32(123456), uint16(10)))
1744
+ assert resp.fingerprint == 123456
1745
+ assert resp.used_for_farmer_rewards is False
1746
+ assert resp.used_for_pool_rewards is False
1747
+
1748
+
1749
+ @pytest.mark.anyio
1750
+ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment):
1751
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1752
+
1753
+ wallet: Wallet = env.wallet_1.wallet
1754
+ wallet_node: WalletNode = env.wallet_1.node
1755
+ client: WalletRpcClient = env.wallet_1.rpc_client
1756
+
1757
+ address = await client.get_next_address(1, True)
1758
+ assert len(address) > 10
1759
+
1760
+ pks = (await client.get_public_keys()).pk_fingerprints
1761
+ assert len(pks) == 1
1762
+
1763
+ await generate_funds(env.full_node.api, env.wallet_1)
1764
+
1765
+ assert (await client.get_height_info()).height > 0
1766
+
1767
+ ph = await wallet.get_new_puzzlehash()
1768
+ addr = encode_puzzle_hash(ph, "txch")
1769
+ tx_amount = uint64(15600000)
1770
+ await env.full_node.api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
1771
+ created_tx = (await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)).transaction
1772
+
1773
+ await time_out_assert(20, tx_in_mempool, True, client, created_tx.name)
1774
+ assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 1
1775
+ await client.delete_unconfirmed_transactions(1)
1776
+ assert len(await wallet.wallet_state_manager.tx_store.get_unconfirmed_for_wallet(1)) == 0
1777
+
1778
+ sk_resp = await client.get_private_key(GetPrivateKey(pks[0]))
1779
+ assert sk_resp.private_key.fingerprint == pks[0]
1780
+ assert sk_resp.private_key.seed is not None
1781
+
1782
+ resp = await client.generate_mnemonic()
1783
+ assert len(resp.mnemonic) == 24
1784
+
1785
+ await client.add_key(AddKey(resp.mnemonic))
1786
+
1787
+ pks = (await client.get_public_keys()).pk_fingerprints
1788
+ assert len(pks) == 2
1789
+
1790
+ await client.log_in(LogIn(pks[1]))
1791
+ sk_resp = await client.get_private_key(GetPrivateKey(pks[1]))
1792
+ assert sk_resp.private_key.fingerprint == pks[1]
1793
+
1794
+ # test hardened keys
1795
+ await _check_delete_key(client=client, wallet_node=wallet_node, farmer_fp=pks[0], pool_fp=pks[1], observer=False)
1796
+
1797
+ # test observer keys
1798
+ await _check_delete_key(client=client, wallet_node=wallet_node, farmer_fp=pks[0], pool_fp=pks[1], observer=True)
1799
+
1800
+ # set farmer to empty string
1801
+ with lock_and_load_config(wallet_node.root_path, "config.yaml") as test_config:
1802
+ test_config["farmer"]["xch_target_address"] = ""
1803
+ save_config(wallet_node.root_path, "config.yaml", test_config)
1804
+
1805
+ # Check key
1806
+ delete_key_resp = await client.check_delete_key(CheckDeleteKey(pks[1]))
1807
+ assert delete_key_resp.fingerprint == pks[1]
1808
+ assert delete_key_resp.used_for_farmer_rewards is False
1809
+ assert delete_key_resp.used_for_pool_rewards is True
1810
+
1811
+ # set farmer and pool to empty string
1812
+ with lock_and_load_config(wallet_node.root_path, "config.yaml") as test_config:
1813
+ test_config["farmer"]["xch_target_address"] = ""
1814
+ test_config["pool"]["xch_target_address"] = ""
1815
+ save_config(wallet_node.root_path, "config.yaml", test_config)
1816
+
1817
+ # Check key
1818
+ delete_key_resp = await client.check_delete_key(CheckDeleteKey(pks[0]))
1819
+ assert delete_key_resp.fingerprint == pks[0]
1820
+ assert delete_key_resp.used_for_farmer_rewards is False
1821
+ assert delete_key_resp.used_for_pool_rewards is False
1822
+
1823
+ await client.delete_key(DeleteKey(pks[0]))
1824
+ await client.log_in(LogIn(uint32(pks[1])))
1825
+ assert len((await client.get_public_keys()).pk_fingerprints) == 1
1826
+
1827
+ assert not (await client.get_sync_status()).synced
1828
+
1829
+ wallets = await client.get_wallets()
1830
+ assert len(wallets) == 1
1831
+ assert await get_unconfirmed_balance(client, int(wallets[0]["id"])) == 0
1832
+
1833
+ with pytest.raises(ValueError):
1834
+ await client.send_transaction(wallets[0]["id"], uint64(100), addr, DEFAULT_TX_CONFIG)
1835
+
1836
+ # Delete all keys
1837
+ await client.delete_all_keys()
1838
+ assert len((await client.get_public_keys()).pk_fingerprints) == 0
1839
+
1840
+
1841
+ @pytest.mark.anyio
1842
+ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment):
1843
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1844
+
1845
+ wallet_2: Wallet = env.wallet_2.wallet
1846
+ wallet_node: WalletNode = env.wallet_1.node
1847
+ full_node_api: FullNodeSimulator = env.full_node.api
1848
+ client: WalletRpcClient = env.wallet_1.rpc_client
1849
+ client_2: WalletRpcClient = env.wallet_2.rpc_client
1850
+
1851
+ funds = await generate_funds(full_node_api, env.wallet_1)
1852
+
1853
+ addr = encode_puzzle_hash(await wallet_2.get_new_puzzlehash(), "txch")
1854
+ coin_300: list[Coin]
1855
+ tx_amounts: list[uint64] = [uint64(1000), uint64(300), uint64(1000), uint64(1000), uint64(10000)]
1856
+ for tx_amount in tx_amounts:
1857
+ funds -= tx_amount
1858
+ # create coins for tests
1859
+ tx = (await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)).transaction
1860
+ spend_bundle = tx.spend_bundle
1861
+ assert spend_bundle is not None
1862
+ for coin in spend_bundle.additions():
1863
+ if coin.amount == uint64(300):
1864
+ coin_300 = [coin]
1865
+
1866
+ await time_out_assert(20, tx_in_mempool, True, client, tx.name)
1867
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
1868
+ await time_out_assert(20, get_confirmed_balance, funds, client, 1)
1869
+
1870
+ # test min coin amount
1871
+ min_coins: list[Coin] = await client_2.select_coins(
1872
+ amount=1000,
1873
+ wallet_id=1,
1874
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(min_coin_amount=uint64(1001)),
1875
+ )
1876
+ assert min_coins is not None
1877
+ assert len(min_coins) == 1 and min_coins[0].amount == uint64(10000)
1878
+
1879
+ # test max coin amount
1880
+ max_coins: list[Coin] = await client_2.select_coins(
1881
+ amount=2000,
1882
+ wallet_id=1,
1883
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
1884
+ min_coin_amount=uint64(999), max_coin_amount=uint64(9999)
1885
+ ),
1886
+ )
1887
+ assert max_coins is not None
1888
+ assert len(max_coins) == 2 and max_coins[0].amount == uint64(1000)
1889
+
1890
+ # test excluded coin amounts
1891
+ non_1000_amt: int = sum(a for a in tx_amounts if a != 1000)
1892
+ excluded_amt_coins: list[Coin] = await client_2.select_coins(
1893
+ amount=non_1000_amt,
1894
+ wallet_id=1,
1895
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_amounts=[uint64(1000)]),
1896
+ )
1897
+ assert excluded_amt_coins is not None
1898
+ assert (
1899
+ len(excluded_amt_coins) == len(tuple(a for a in tx_amounts if a != 1000))
1900
+ and sum(c.amount for c in excluded_amt_coins) == non_1000_amt
1901
+ )
1902
+
1903
+ # test excluded coins
1904
+ with pytest.raises(ValueError):
1905
+ await client_2.select_coins(
1906
+ amount=5000,
1907
+ wallet_id=1,
1908
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
1909
+ excluded_coin_ids=[c.name() for c in min_coins]
1910
+ ),
1911
+ )
1912
+ excluded_test = await client_2.select_coins(
1913
+ amount=1300,
1914
+ wallet_id=1,
1915
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_ids=[c.name() for c in coin_300]),
1916
+ )
1917
+ assert len(excluded_test) == 2
1918
+ for coin in excluded_test:
1919
+ assert coin != coin_300[0]
1920
+
1921
+ # test backwards compatibility in the RPC
1922
+ identical_test = (
1923
+ await client_2.fetch(
1924
+ "select_coins",
1925
+ {
1926
+ "amount": 1300,
1927
+ "wallet_id": 1,
1928
+ "exclude_coins": [c.to_json_dict() for c in coin_300],
1929
+ },
1930
+ )
1931
+ )["coins"]
1932
+ assert len(identical_test) == 2
1933
+ for coin in identical_test:
1934
+ assert coin != coin_300[0]
1935
+
1936
+ # test get coins
1937
+ all_coins, _, _ = await client_2.get_spendable_coins(
1938
+ wallet_id=1,
1939
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
1940
+ excluded_coin_ids=[c.name() for c in excluded_amt_coins]
1941
+ ),
1942
+ )
1943
+ assert set(excluded_amt_coins).intersection({rec.coin for rec in all_coins}) == set()
1944
+ all_coins, _, _ = await client_2.get_spendable_coins(
1945
+ wallet_id=1,
1946
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_amounts=[uint64(1000)]),
1947
+ )
1948
+ assert len([rec for rec in all_coins if rec.coin.amount == 1000]) == 0
1949
+ all_coins_2, _, _ = await client_2.get_spendable_coins(
1950
+ wallet_id=1,
1951
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(max_coin_amount=uint64(999)),
1952
+ )
1953
+ assert all_coins_2[0].coin == coin_300[0]
1954
+ with pytest.raises(ValueError): # validate fail on invalid coin id.
1955
+ await client_2.get_spendable_coins(
1956
+ wallet_id=1,
1957
+ coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_ids=[b"a"]),
1958
+ )
1959
+
1960
+
1961
+ @pytest.mark.anyio
1962
+ async def test_get_coin_records_rpc(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
1963
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
1964
+ wallet_node: WalletNode = env.wallet_1.node
1965
+ client: WalletRpcClient = env.wallet_1.rpc_client
1966
+ store = wallet_node.wallet_state_manager.coin_store
1967
+
1968
+ for record in [record_1, record_2, record_3, record_4, record_5, record_6, record_7, record_8, record_9]:
1969
+ await store.add_coin_record(record)
1970
+
1971
+ async def run_test_case(
1972
+ test_case: str,
1973
+ test_request: GetCoinRecords,
1974
+ test_total_count: Optional[int],
1975
+ test_records: list[WalletCoinRecord],
1976
+ ):
1977
+ response = await client.get_coin_records(test_request)
1978
+ assert response["coin_records"] == [coin.to_json_dict_parsed_metadata() for coin in test_records], test_case
1979
+ assert response["total_count"] == test_total_count, test_case
1980
+
1981
+ for name, tests in {
1982
+ "offset_limit": get_coin_records_offset_limit_tests,
1983
+ "wallet_id": get_coin_records_wallet_id_tests,
1984
+ "wallet_type": get_coin_records_wallet_type_tests,
1985
+ "coin_type": get_coin_records_coin_type_tests,
1986
+ "coin_id_filter": get_coin_records_coin_id_filter_tests,
1987
+ "puzzle_hash_filter": get_coin_records_puzzle_hash_filter_tests,
1988
+ "parent_coin_id_filter": get_coin_records_parent_coin_id_filter_tests,
1989
+ "amount_filter": get_coin_records_amount_filter_tests,
1990
+ "amount_range": get_coin_records_amount_range_tests,
1991
+ "confirmed_range": get_coin_records_confirmed_range_tests,
1992
+ "spent_range": get_coin_records_spent_range_tests,
1993
+ "order": get_coin_records_order_tests,
1994
+ "reverse": get_coin_records_reverse_tests,
1995
+ }.items():
1996
+ for i, (request, expected_records) in enumerate(tests):
1997
+ await run_test_case(f"{name}-{i}", request, None, expected_records)
1998
+
1999
+ for name, total_count_tests in {
2000
+ "total_count": get_coin_records_include_total_count_tests,
2001
+ "mixed": get_coin_records_mixed_tests,
2002
+ }.items():
2003
+ for i, (request, expected_total_count, expected_records) in enumerate(total_count_tests):
2004
+ await run_test_case(f"{name}-{i}", request, expected_total_count, expected_records)
2005
+
2006
+
2007
+ @pytest.mark.anyio
2008
+ async def test_get_coin_records_rpc_limits(
2009
+ wallet_rpc_environment: WalletRpcTestEnvironment,
2010
+ seeded_random: random.Random,
2011
+ ) -> None:
2012
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2013
+ wallet_node: WalletNode = env.wallet_1.node
2014
+ client: WalletRpcClient = env.wallet_1.rpc_client
2015
+ rpc_server: Optional[RpcServer] = wallet_rpc_environment.wallet_1.service.rpc_server
2016
+ assert rpc_server is not None
2017
+ api: WalletRpcApi = cast(WalletRpcApi, rpc_server.rpc_api)
2018
+ store = wallet_node.wallet_state_manager.coin_store
2019
+
2020
+ # Adjust the limits for faster testing
2021
+ WalletRpcApi.max_get_coin_records_limit = uint32(5)
2022
+ WalletRpcApi.max_get_coin_records_filter_items = uint32(5)
2023
+
2024
+ max_coins = api.max_get_coin_records_limit * 10
2025
+ coin_records = [
2026
+ WalletCoinRecord(
2027
+ Coin(bytes32.random(seeded_random), bytes32.random(seeded_random), uint64(seeded_random.randrange(2**64))),
2028
+ uint32(seeded_random.randrange(2**32)),
2029
+ uint32(0),
2030
+ False,
2031
+ False,
2032
+ WalletType.STANDARD_WALLET,
2033
+ uint32(0),
2034
+ CoinType.NORMAL,
2035
+ None,
2036
+ )
2037
+ for _ in range(max_coins)
2038
+ ]
2039
+ for record in coin_records:
2040
+ await store.add_coin_record(record)
2041
+
2042
+ limit = api.max_get_coin_records_limit
2043
+ response_records = []
2044
+ for i in range(int(max_coins / api.max_get_coin_records_limit)):
2045
+ offset = uint32(api.max_get_coin_records_limit * i)
2046
+ response = await client.get_coin_records(GetCoinRecords(limit=limit, offset=offset, include_total_count=True))
2047
+ response_records.extend(list(response["coin_records"]))
2048
+
2049
+ assert len(response_records) == max_coins
2050
+ # Make sure we got all expected records
2051
+ parsed_records = [coin.to_json_dict_parsed_metadata() for coin in coin_records]
2052
+ for expected_record in parsed_records:
2053
+ assert expected_record in response_records
2054
+
2055
+ # Request coins with the max number of filter items
2056
+ max_filter_items = api.max_get_coin_records_filter_items
2057
+ filter_records = coin_records[:max_filter_items]
2058
+ coin_id_filter = HashFilter.include([coin.name() for coin in filter_records])
2059
+ puzzle_hash_filter = HashFilter.include([coin.coin.puzzle_hash for coin in filter_records])
2060
+ parent_coin_id_filter = HashFilter.include([coin.coin.parent_coin_info for coin in filter_records])
2061
+ amount_filter = AmountFilter.include([uint64(coin.coin.amount) for coin in coin_records[:max_filter_items]])
2062
+ for request in [
2063
+ GetCoinRecords(coin_id_filter=coin_id_filter),
2064
+ GetCoinRecords(puzzle_hash_filter=puzzle_hash_filter),
2065
+ GetCoinRecords(parent_coin_id_filter=parent_coin_id_filter),
2066
+ GetCoinRecords(amount_filter=amount_filter),
2067
+ GetCoinRecords(
2068
+ coin_id_filter=coin_id_filter,
2069
+ puzzle_hash_filter=puzzle_hash_filter,
2070
+ parent_coin_id_filter=parent_coin_id_filter,
2071
+ amount_filter=amount_filter,
2072
+ ),
2073
+ ]:
2074
+ response = await client.get_coin_records(request)
2075
+ parsed_records = [coin.to_json_dict_parsed_metadata() for coin in filter_records]
2076
+ for expected_record in parsed_records:
2077
+ assert expected_record in response["coin_records"]
2078
+
2079
+
2080
+ @pytest.mark.anyio
2081
+ async def test_get_coin_records_rpc_failures(
2082
+ wallet_rpc_environment: WalletRpcTestEnvironment,
2083
+ seeded_random: random.Random,
2084
+ ) -> None:
2085
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2086
+ client: WalletRpcClient = env.wallet_1.rpc_client
2087
+ rpc_server: Optional[RpcServer] = wallet_rpc_environment.wallet_1.service.rpc_server
2088
+ assert rpc_server is not None
2089
+ api = cast(WalletRpcApi, rpc_server.rpc_api)
2090
+
2091
+ too_many_hashes = [bytes32.random(seeded_random) for _ in range(api.max_get_coin_records_filter_items + 1)]
2092
+ too_many_amounts = [
2093
+ uint64(uint64(seeded_random.randrange(2**64))) for _ in range(api.max_get_coin_records_filter_items + 1)
2094
+ ]
2095
+ # Run requests which exceeds the allowed limit and contain too much filter items
2096
+ for name, request in {
2097
+ "limit": GetCoinRecords(limit=uint32(api.max_get_coin_records_limit + 1)),
2098
+ "coin_id_filter": GetCoinRecords(coin_id_filter=HashFilter.include(too_many_hashes)),
2099
+ "puzzle_hash_filter": GetCoinRecords(puzzle_hash_filter=HashFilter.include(too_many_hashes)),
2100
+ "parent_coin_id_filter": GetCoinRecords(parent_coin_id_filter=HashFilter.include(too_many_hashes)),
2101
+ "amount_filter": GetCoinRecords(amount_filter=AmountFilter.include(too_many_amounts)),
2102
+ }.items():
2103
+ with pytest.raises(ValueError, match=name):
2104
+ await client.get_coin_records(request)
2105
+
2106
+ # Type validation is handled via `Streamable.from_json_dict` but the below should make at least sure it triggers.
2107
+ for field, value in {
2108
+ "offset": "invalid",
2109
+ "limit": "invalid",
2110
+ "wallet_id": "invalid",
2111
+ "wallet_type": 100,
2112
+ "coin_type": 100,
2113
+ "coin_id_filter": "invalid",
2114
+ "puzzle_hash_filter": "invalid",
2115
+ "parent_coin_id_filter": "invalid",
2116
+ "amount_filter": "invalid",
2117
+ "amount_range": "invalid",
2118
+ "confirmed_range": "invalid",
2119
+ "spent_range": "invalid",
2120
+ "order": 8,
2121
+ }.items():
2122
+ with pytest.raises((ConversionError, InvalidTypeError, ValueError)):
2123
+ json_dict = GetCoinRecords().to_json_dict()
2124
+ json_dict[field] = value
2125
+ await api.get_coin_records(json_dict)
2126
+
2127
+
2128
+ @pytest.mark.anyio
2129
+ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironment):
2130
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2131
+
2132
+ wallet_2: Wallet = env.wallet_2.wallet
2133
+ wallet_node: WalletNode = env.wallet_1.node
2134
+ full_node_api: FullNodeSimulator = env.full_node.api
2135
+ client: WalletRpcClient = env.wallet_1.rpc_client
2136
+ client_2: WalletRpcClient = env.wallet_2.rpc_client
2137
+
2138
+ await generate_funds(full_node_api, env.wallet_1)
2139
+
2140
+ env.wallet_2.node.config["enable_notifications"] = True
2141
+ env.wallet_2.node.config["required_notification_amount"] = 100000000000
2142
+ tx = await client.send_notification(
2143
+ await wallet_2.get_new_puzzlehash(),
2144
+ b"hello",
2145
+ uint64(100000000000),
2146
+ fee=uint64(100000000000),
2147
+ )
2148
+
2149
+ assert tx.spend_bundle is not None
2150
+ await time_out_assert(
2151
+ 5,
2152
+ full_node_api.full_node.mempool_manager.get_spendbundle,
2153
+ tx.spend_bundle,
2154
+ tx.spend_bundle.name(),
2155
+ )
2156
+ await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
2157
+ await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(100000000000))
2158
+
2159
+ notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
2160
+ assert [notification] == (await client_2.get_notifications(GetNotifications([notification.id]))).notifications
2161
+ assert [] == (await client_2.get_notifications(GetNotifications(None, uint32(0), uint32(0)))).notifications
2162
+ assert [notification] == (await client_2.get_notifications(GetNotifications(None, None, uint32(1)))).notifications
2163
+ assert [] == (await client_2.get_notifications(GetNotifications(None, uint32(1), None))).notifications
2164
+ assert [notification] == (await client_2.get_notifications(GetNotifications(None, None, None))).notifications
2165
+ assert await client_2.delete_notifications()
2166
+ assert [] == (await client_2.get_notifications(GetNotifications([notification.id]))).notifications
2167
+
2168
+ tx = await client.send_notification(
2169
+ await wallet_2.get_new_puzzlehash(),
2170
+ b"hello",
2171
+ uint64(100000000000),
2172
+ fee=uint64(100000000000),
2173
+ )
2174
+
2175
+ assert tx.spend_bundle is not None
2176
+ await time_out_assert(
2177
+ 5,
2178
+ full_node_api.full_node.mempool_manager.get_spendbundle,
2179
+ tx.spend_bundle,
2180
+ tx.spend_bundle.name(),
2181
+ )
2182
+ await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
2183
+ await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(200000000000))
2184
+
2185
+ notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
2186
+ assert await client_2.delete_notifications([notification.id])
2187
+ assert [] == (await client_2.get_notifications(GetNotifications([notification.id]))).notifications
2188
+
2189
+
2190
+ # The signatures below were made from an ephemeral key pair that isn't included in the test code.
2191
+ # When modifying this test, any key can be used to generate signatures. Only the pubkey needs to
2192
+ # be included in the test code.
2193
+ #
2194
+ # Example 1:
2195
+ # $ chia keys generate
2196
+ # $ chia keys sign -d 'hello world' -t 'm/12381/8444/1/1'
2197
+ #
2198
+ # Example 2:
2199
+ # $ chia wallet get_address
2200
+ # xch1vk0dj7cx7d638h80mcuw70xqlnr56pmuhzajemn5ym02vhl3mzyqrrd4wp
2201
+ # $ chia wallet sign_message -m $(echo -n 'hello world' | xxd -p)
2202
+ # -a xch1vk0dj7cx7d638h80mcuw70xqlnr56pmuhzajemn5ym02vhl3mzyqrrd4wp
2203
+ #
2204
+ @pytest.mark.parametrize(
2205
+ ["rpc_request", "rpc_response"],
2206
+ [
2207
+ # Valid signatures
2208
+ (
2209
+ # chia keys sign -d "Let's eat, Grandma" -t "m/12381/8444/1/1"
2210
+ {
2211
+ "message": "4c65742773206561742c204772616e646d61", # Let's eat, Grandma
2212
+ "pubkey": (
2213
+ "89d8e2a225c2ff543222bd0f2ba457a44acbdd147e4dfa02"
2214
+ "eadaef73eae49450dc708fd7c86800b60e8bc456e77563e4"
2215
+ ),
2216
+ "signature": (
2217
+ "8006f63537563f038321eeda25f3838613d8f938e95f19d1d19ccbe634e9ee4d69552536aab08b4fe961305"
2218
+ "e534ffddf096199ae936b272dac88c936e8774bfc7a6f24025085026db3b7c3c41b472db3daf99b5e6cabf2"
2219
+ "6034d8782d10ef148d"
2220
+ ),
2221
+ },
2222
+ VerifySignatureResponse(isValid=True),
2223
+ ),
2224
+ (
2225
+ # chia wallet sign_message -m $(echo -n 'Happy happy joy joy' | xxd -p)
2226
+ # -a xch1e2pcue5q7t4sg8gygz3aht369sk78rzzs92zx65ktn9a9qurw35saajvkh
2227
+ {
2228
+ "message": "4861707079206861707079206a6f79206a6f79", # Happy happy joy joy
2229
+ "pubkey": (
2230
+ "8e156d106f1b0ff0ebbe5ab27b1797a19cf3e895a7a435b0"
2231
+ "03a1df2dd477d622be928379625b759ef3b388b286ee8658"
2232
+ ),
2233
+ "signature": (
2234
+ "a804111f80be2ed0d4d3fdd139c8fe20cd506b99b03592563d85292abcbb9cd6ff6df2e7a13093e330d66aa"
2235
+ "5218bbe0e17677c9a23a9f18dbe488b7026be59d476161f5e6f0eea109cd7be22b1f74fda9c80c6b845ecc6"
2236
+ "91246eb1c7f1b66a6a"
2237
+ ),
2238
+ "signing_mode": SigningMode.CHIP_0002.value,
2239
+ },
2240
+ VerifySignatureResponse(isValid=True),
2241
+ ),
2242
+ (
2243
+ # chia wallet sign_message -m $(echo -n 'Happy happy joy joy' | xxd -p)
2244
+ # -a xch1e2pcue5q7t4sg8gygz3aht369sk78rzzs92zx65ktn9a9qurw35saajvkh
2245
+ {
2246
+ "message": "4861707079206861707079206a6f79206a6f79", # Happy happy joy joy
2247
+ "pubkey": (
2248
+ "8e156d106f1b0ff0ebbe5ab27b1797a19cf3e895a7a435b0"
2249
+ "03a1df2dd477d622be928379625b759ef3b388b286ee8658"
2250
+ ),
2251
+ "signature": (
2252
+ "a804111f80be2ed0d4d3fdd139c8fe20cd506b99b03592563d85292abcbb9cd6ff6df2e7a13093e330d66aa"
2253
+ "5218bbe0e17677c9a23a9f18dbe488b7026be59d476161f5e6f0eea109cd7be22b1f74fda9c80c6b845ecc6"
2254
+ "91246eb1c7f1b66a6a"
2255
+ ),
2256
+ "signing_mode": SigningMode.CHIP_0002.value,
2257
+ "address": "xch1e2pcue5q7t4sg8gygz3aht369sk78rzzs92zx65ktn9a9qurw35saajvkh",
2258
+ },
2259
+ VerifySignatureResponse(isValid=True),
2260
+ ),
2261
+ (
2262
+ {
2263
+ "message": "4f7a6f6e65", # Ozone
2264
+ "pubkey": (
2265
+ "8fba5482e6c798a06ee1fd95deaaa83f11c46da06006ab35"
2266
+ "24e917f4e116c2bdec69d6098043ca568290ac366e5e2dc5"
2267
+ ),
2268
+ "signature": (
2269
+ "92a5124d53b74e4197d075277d0b31eda1571353415c4a87952035aa392d4e9206b35e4af959e7135e45db1"
2270
+ "c884b8b970f9cbffd42291edc1acdb124554f04608b8d842c19e1404d306f881fa79c0e287bdfcf36a6e5da"
2271
+ "334981b974a6cebfd0"
2272
+ ),
2273
+ "signing_mode": SigningMode.CHIP_0002_P2_DELEGATED_CONDITIONS.value,
2274
+ "address": "xch1hh9phcc8tt703dla70qthlhrxswy88va04zvc7vd8cx2v6a5ywyst8mgul",
2275
+ },
2276
+ VerifySignatureResponse(isValid=True),
2277
+ ),
2278
+ # Negative tests
2279
+ (
2280
+ # Message was modified
2281
+ {
2282
+ "message": "4c6574277320656174204772616e646d61", # Let's eat Grandma
2283
+ "pubkey": (
2284
+ "89d8e2a225c2ff543222bd0f2ba457a44acbdd147e4dfa02"
2285
+ "eadaef73eae49450dc708fd7c86800b60e8bc456e77563e4"
2286
+ ),
2287
+ "signature": (
2288
+ "8006f63537563f038321eeda25f3838613d8f938e95f19d1d19ccbe634e9ee4d69552536aab08b4fe961305"
2289
+ "e534ffddf096199ae936b272dac88c936e8774bfc7a6f24025085026db3b7c3c41b472db3daf99b5e6cabf2"
2290
+ "6034d8782d10ef148d"
2291
+ ),
2292
+ },
2293
+ VerifySignatureResponse(isValid=False, error="Signature is invalid."),
2294
+ ),
2295
+ (
2296
+ # Valid signature but address doesn't match pubkey
2297
+ {
2298
+ "message": "4861707079206861707079206a6f79206a6f79", # Happy happy joy joy
2299
+ "pubkey": (
2300
+ "8e156d106f1b0ff0ebbe5ab27b1797a19cf3e895a7a435b0"
2301
+ "03a1df2dd477d622be928379625b759ef3b388b286ee8658"
2302
+ ),
2303
+ "signature": (
2304
+ "a804111f80be2ed0d4d3fdd139c8fe20cd506b99b03592563d85292abcbb9cd6ff6df2e7a13093e330d66aa"
2305
+ "5218bbe0e17677c9a23a9f18dbe488b7026be59d476161f5e6f0eea109cd7be22b1f74fda9c80c6b845ecc6"
2306
+ "91246eb1c7f1b66a6a"
2307
+ ),
2308
+ "signing_mode": SigningMode.CHIP_0002.value,
2309
+ "address": "xch1d0rekc2javy5gpruzmcnk4e4qq834jzlvxt5tcgl2ylt49t26gdsjen7t0",
2310
+ },
2311
+ VerifySignatureResponse(isValid=False, error="Public key doesn't match the address"),
2312
+ ),
2313
+ (
2314
+ {
2315
+ "message": "4f7a6f6e65", # Ozone
2316
+ "pubkey": (
2317
+ "8fba5482e6c798a06ee1fd95deaaa83f11c46da06006ab35"
2318
+ "24e917f4e116c2bdec69d6098043ca568290ac366e5e2dc5"
2319
+ ),
2320
+ "signature": (
2321
+ "92a5124d53b74e4197d075277d0b31eda1571353415c4a87952035aa392d4e9206b35e4af959e7135e45db1"
2322
+ "c884b8b970f9cbffd42291edc1acdb124554f04608b8d842c19e1404d306f881fa79c0e287bdfcf36a6e5da"
2323
+ "334981b974a6cebfd0"
2324
+ ),
2325
+ "address": "xch1hh9phcc8tt703dla70qthlhrxswy88va04zvc7vd8cx2v6a5ywyst8mgul",
2326
+ },
2327
+ VerifySignatureResponse(isValid=False, error="Public key doesn't match the address"),
2328
+ ),
2329
+ ],
2330
+ )
2331
+ @pytest.mark.parametrize("prefix_hex_strings", [True, False], ids=["with 0x", "no 0x"])
2332
+ @pytest.mark.anyio
2333
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2334
+ async def test_verify_signature(
2335
+ wallet_rpc_environment: WalletRpcTestEnvironment,
2336
+ rpc_request: dict[str, Any],
2337
+ rpc_response: dict[str, Any],
2338
+ prefix_hex_strings: bool,
2339
+ ):
2340
+ rpc_server: Optional[RpcServer] = wallet_rpc_environment.wallet_1.service.rpc_server
2341
+ assert rpc_server is not None
2342
+ updated_request = rpc_request.copy()
2343
+ updated_request["pubkey"] = ("0x" if prefix_hex_strings else "") + updated_request["pubkey"]
2344
+ updated_request["signature"] = ("0x" if prefix_hex_strings else "") + updated_request["signature"]
2345
+ res = await wallet_rpc_environment.wallet_1.rpc_client.verify_signature(
2346
+ VerifySignature.from_json_dict(updated_request)
2347
+ )
2348
+ assert res == rpc_response
2349
+
2350
+
2351
+ @pytest.mark.anyio
2352
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2353
+ async def test_set_auto_claim(wallet_rpc_environment: WalletRpcTestEnvironment):
2354
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2355
+ full_node_api: FullNodeSimulator = env.full_node.api
2356
+ rpc_server: Optional[RpcServer] = wallet_rpc_environment.wallet_1.service.rpc_server
2357
+ await generate_funds(full_node_api, env.wallet_1)
2358
+ assert rpc_server is not None
2359
+ api: WalletRpcApi = cast(WalletRpcApi, rpc_server.rpc_api)
2360
+ req = {"enabled": False, "tx_fee": -1, "min_amount": 100}
2361
+ has_exception = False
2362
+ try:
2363
+ # Manually using API to test error condition
2364
+ await api.set_auto_claim(req)
2365
+ except ConversionError:
2366
+ has_exception = True
2367
+ assert has_exception
2368
+ req = {"enabled": False, "batch_size": 0, "min_amount": 100}
2369
+ res = await env.wallet_1.rpc_client.set_auto_claim(
2370
+ AutoClaimSettings(enabled=False, batch_size=uint16(0), min_amount=uint64(100))
2371
+ )
2372
+ assert not res.enabled
2373
+ assert res.tx_fee == 0
2374
+ assert res.min_amount == 100
2375
+ assert res.batch_size == 50
2376
+
2377
+
2378
+ @pytest.mark.anyio
2379
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2380
+ async def test_get_auto_claim(wallet_rpc_environment: WalletRpcTestEnvironment):
2381
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2382
+ full_node_api: FullNodeSimulator = env.full_node.api
2383
+ rpc_server: Optional[RpcServer] = wallet_rpc_environment.wallet_1.service.rpc_server
2384
+ await generate_funds(full_node_api, env.wallet_1)
2385
+ assert rpc_server is not None
2386
+ res = await env.wallet_1.rpc_client.get_auto_claim()
2387
+ assert not res.enabled
2388
+ assert res.tx_fee == 0
2389
+ assert res.min_amount == 0
2390
+ assert res.batch_size == 50
2391
+
2392
+
2393
+ @pytest.mark.anyio
2394
+ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTestEnvironment):
2395
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2396
+ full_node_api: FullNodeSimulator = env.full_node.api
2397
+ client: WalletRpcClient = env.wallet_1.rpc_client
2398
+ await generate_funds(full_node_api, env.wallet_1)
2399
+ wc = env.wallet_1.rpc_client
2400
+ await wc.create_new_did_wallet(1, DEFAULT_TX_CONFIG, 0)
2401
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2402
+ await farm_transaction_block(full_node_api, env.wallet_1.node)
2403
+ await time_out_assert(20, check_client_synced, True, wc)
2404
+
2405
+ nft_wallet = await wc.create_new_nft_wallet(None)
2406
+ nft_wallet_id = nft_wallet["wallet_id"]
2407
+ address = await wc.get_next_address(env.wallet_1.wallet.id(), True)
2408
+ await wc.mint_nft(
2409
+ nft_wallet_id,
2410
+ tx_config=DEFAULT_TX_CONFIG,
2411
+ royalty_address=address,
2412
+ target_address=address,
2413
+ hash="deadbeef",
2414
+ uris=["http://test.nft"],
2415
+ )
2416
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2417
+ await farm_transaction_block(full_node_api, env.wallet_1.node)
2418
+ await time_out_assert(20, check_client_synced, True, wc)
2419
+
2420
+ wallet_node: WalletNode = env.wallet_1.node
2421
+ wallet_node_2: WalletNode = env.wallet_2.node
2422
+ # Test Clawback resync
2423
+ tx = (
2424
+ await wc.send_transaction(
2425
+ wallet_id=1,
2426
+ amount=uint64(500),
2427
+ address=address,
2428
+ tx_config=DEFAULT_TX_CONFIG,
2429
+ fee=uint64(0),
2430
+ puzzle_decorator_override=[{"decorator": "CLAWBACK", "clawback_timelock": 5}],
2431
+ )
2432
+ ).transaction
2433
+ clawback_coin_id = tx.additions[0].name()
2434
+ assert tx.spend_bundle is not None
2435
+ await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
2436
+ await time_out_assert(20, check_client_synced, True, wc)
2437
+ await asyncio.sleep(10)
2438
+ resp = await wc.spend_clawback_coins([clawback_coin_id], 0)
2439
+ assert resp["success"]
2440
+ assert len(resp["transaction_ids"]) == 1
2441
+ await time_out_assert_not_none(
2442
+ 10, full_node_api.full_node.mempool_manager.get_spendbundle, bytes32.from_hexstr(resp["transaction_ids"][0])
2443
+ )
2444
+ await farm_transaction_block(full_node_api, wallet_node)
2445
+ await time_out_assert(20, check_client_synced, True, wc)
2446
+ wallet_node_2._close()
2447
+ await wallet_node_2._await_closed()
2448
+ # set flag to reset wallet sync data on start
2449
+ await client.set_wallet_resync_on_startup(SetWalletResyncOnStartup())
2450
+ fingerprint = wallet_node.logged_in_fingerprint
2451
+ assert wallet_node._wallet_state_manager
2452
+ # 2 reward coins, 1 DID, 1 NFT, 1 clawbacked coin
2453
+ assert len(await wallet_node._wallet_state_manager.coin_store.get_all_unspent_coins()) == 5
2454
+ assert await wallet_node._wallet_state_manager.nft_store.count() == 1
2455
+ # standard wallet, did wallet, nft wallet, did nft wallet
2456
+ assert len(await wallet_node.wallet_state_manager.user_store.get_all_wallet_info_entries()) == 4
2457
+ before_txs = await wallet_node.wallet_state_manager.tx_store.get_all_transactions()
2458
+ wallet_node._close()
2459
+ await wallet_node._await_closed()
2460
+ config = load_config(wallet_node.root_path, "config.yaml")
2461
+ # check that flag was set in config file
2462
+ assert config["wallet"]["reset_sync_for_fingerprint"] == fingerprint
2463
+ new_config = wallet_node.config.copy()
2464
+ new_config["reset_sync_for_fingerprint"] = config["wallet"]["reset_sync_for_fingerprint"]
2465
+ wallet_node_2.config = new_config
2466
+ wallet_node_2.root_path = wallet_node.root_path
2467
+ wallet_node_2.local_keychain = wallet_node.local_keychain
2468
+ # use second node to start the same wallet, reusing config and db
2469
+ await wallet_node_2._start_with_fingerprint(fingerprint)
2470
+ assert wallet_node_2._wallet_state_manager
2471
+ after_txs = await wallet_node_2.wallet_state_manager.tx_store.get_all_transactions()
2472
+ # transactions should be the same
2473
+ assert after_txs == before_txs
2474
+ # Check clawback
2475
+ clawback_tx = await wallet_node_2.wallet_state_manager.tx_store.get_transaction_record(clawback_coin_id)
2476
+ assert clawback_tx is not None
2477
+ assert clawback_tx.confirmed
2478
+ # only coin_store was populated in this case, but now should be empty
2479
+ assert len(await wallet_node_2._wallet_state_manager.coin_store.get_all_unspent_coins()) == 0
2480
+ assert await wallet_node_2._wallet_state_manager.nft_store.count() == 0
2481
+ # we don't delete wallets
2482
+ assert len(await wallet_node_2.wallet_state_manager.user_store.get_all_wallet_info_entries()) == 4
2483
+ updated_config = load_config(wallet_node.root_path, "config.yaml")
2484
+ # check that it's disabled after reset
2485
+ assert updated_config["wallet"].get("reset_sync_for_fingerprint") is None
2486
+ wallet_node_2._close()
2487
+ await wallet_node_2._await_closed()
2488
+
2489
+
2490
+ @pytest.mark.anyio
2491
+ async def test_set_wallet_resync_on_startup_disable(wallet_rpc_environment: WalletRpcTestEnvironment):
2492
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2493
+ full_node_api: FullNodeSimulator = env.full_node.api
2494
+ client: WalletRpcClient = env.wallet_1.rpc_client
2495
+ await generate_funds(full_node_api, env.wallet_1)
2496
+ wallet_node: WalletNode = env.wallet_1.node
2497
+ wallet_node_2: WalletNode = env.wallet_2.node
2498
+ wallet_node_2._close()
2499
+ await wallet_node_2._await_closed()
2500
+ # set flag to reset wallet sync data on start
2501
+ await client.set_wallet_resync_on_startup(SetWalletResyncOnStartup())
2502
+ fingerprint = wallet_node.logged_in_fingerprint
2503
+ assert wallet_node._wallet_state_manager
2504
+ assert len(await wallet_node._wallet_state_manager.coin_store.get_all_unspent_coins()) == 2
2505
+ before_txs = await wallet_node.wallet_state_manager.tx_store.get_all_transactions()
2506
+ await client.set_wallet_resync_on_startup(SetWalletResyncOnStartup(False))
2507
+ wallet_node._close()
2508
+ await wallet_node._await_closed()
2509
+ config = load_config(wallet_node.root_path, "config.yaml")
2510
+ # check that flag was set in config file
2511
+ assert config["wallet"].get("reset_sync_for_fingerprint") is None
2512
+ new_config = wallet_node.config.copy()
2513
+ new_config["reset_sync_for_fingerprint"] = config["wallet"].get("reset_sync_for_fingerprint")
2514
+ wallet_node_2.config = new_config
2515
+ wallet_node_2.root_path = wallet_node.root_path
2516
+ wallet_node_2.local_keychain = wallet_node.local_keychain
2517
+ # use second node to start the same wallet, reusing config and db
2518
+ await wallet_node_2._start_with_fingerprint(fingerprint)
2519
+ assert wallet_node_2._wallet_state_manager
2520
+ after_txs = await wallet_node_2.wallet_state_manager.tx_store.get_all_transactions()
2521
+ # transactions should be the same
2522
+ assert after_txs == before_txs
2523
+ # only coin_store was populated in this case, but now should be empty
2524
+ assert len(await wallet_node_2._wallet_state_manager.coin_store.get_all_unspent_coins()) == 2
2525
+ wallet_node_2._close()
2526
+ await wallet_node_2._await_closed()
2527
+
2528
+
2529
+ @pytest.mark.anyio
2530
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2531
+ async def test_set_wallet_resync_schema(wallet_rpc_environment: WalletRpcTestEnvironment):
2532
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2533
+ full_node_api: FullNodeSimulator = env.full_node.api
2534
+ await generate_funds(full_node_api, env.wallet_1)
2535
+ wallet_node: WalletNode = env.wallet_1.node
2536
+ fingerprint = wallet_node.logged_in_fingerprint
2537
+ assert fingerprint
2538
+ db_path = wallet_node.wallet_state_manager.db_path
2539
+ assert await wallet_node.reset_sync_db(
2540
+ db_path, fingerprint
2541
+ ), "Schema has been changed, reset sync db won't work, please update WalletNode.reset_sync_db function"
2542
+ dbw: DBWrapper2 = wallet_node.wallet_state_manager.db_wrapper
2543
+ conn: aiosqlite.Connection
2544
+ async with dbw.writer() as conn:
2545
+ await conn.execute("CREATE TABLE blah(temp int)")
2546
+ await wallet_node.reset_sync_db(db_path, fingerprint)
2547
+ assert (
2548
+ len(list(await conn.execute_fetchall("SELECT name FROM sqlite_master WHERE type='table' AND name='blah'"))) == 0
2549
+ )
2550
+
2551
+
2552
+ @pytest.mark.anyio
2553
+ async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironment):
2554
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2555
+
2556
+ wallet_node: WalletNode = env.wallet_1.node
2557
+ client: WalletRpcClient = env.wallet_1.rpc_client
2558
+ full_node_api: FullNodeSimulator = env.full_node.api
2559
+ full_node_rpc: FullNodeRpcClient = env.full_node.rpc_client
2560
+
2561
+ await generate_funds(full_node_api, env.wallet_1, 1)
2562
+
2563
+ # Send to a CAT with an anyone can spend TAIL
2564
+ our_ph: bytes32 = await env.wallet_1.wallet.get_new_puzzlehash()
2565
+ cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, Program.to(None).get_tree_hash(), Program.to(1))
2566
+ addr = encode_puzzle_hash(
2567
+ cat_puzzle.get_tree_hash(),
2568
+ "txch",
2569
+ )
2570
+ tx_amount = uint64(100)
2571
+
2572
+ tx = (await client.send_transaction(1, tx_amount, addr, DEFAULT_TX_CONFIG)).transaction
2573
+ transaction_id = tx.name
2574
+ spend_bundle = tx.spend_bundle
2575
+ assert spend_bundle is not None
2576
+
2577
+ await time_out_assert(20, tx_in_mempool, True, client, transaction_id)
2578
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
2579
+
2580
+ # Do the eve spend back to our wallet
2581
+ cat_coin = next(c for c in spend_bundle.additions() if c.amount == tx_amount)
2582
+ eve_spend = WalletSpendBundle(
2583
+ [
2584
+ make_spend(
2585
+ cat_coin,
2586
+ cat_puzzle,
2587
+ Program.to(
2588
+ [
2589
+ Program.to([[51, our_ph, tx_amount, [our_ph]], [51, None, -113, None, None]]),
2590
+ None,
2591
+ cat_coin.name(),
2592
+ coin_as_list(cat_coin),
2593
+ [cat_coin.parent_coin_info, Program.to(1).get_tree_hash(), cat_coin.amount],
2594
+ 0,
2595
+ 0,
2596
+ ]
2597
+ ),
2598
+ )
2599
+ ],
2600
+ G2Element(),
2601
+ )
2602
+ await full_node_rpc.push_tx(eve_spend)
2603
+ await farm_transaction(full_node_api, wallet_node, eve_spend)
2604
+
2605
+ # Make sure we have the CAT
2606
+ res = await client.create_wallet_for_existing_cat(Program.to(None).get_tree_hash())
2607
+ assert res["success"]
2608
+ cat_wallet_id = res["wallet_id"]
2609
+ await time_out_assert(20, get_confirmed_balance, tx_amount, client, cat_wallet_id)
2610
+
2611
+ # Attempt to melt it fully
2612
+ tx = (
2613
+ await client.cat_spend(
2614
+ cat_wallet_id,
2615
+ amount=uint64(0),
2616
+ tx_config=DEFAULT_TX_CONFIG,
2617
+ inner_address=encode_puzzle_hash(our_ph, "txch"),
2618
+ cat_discrepancy=(tx_amount * -1, Program.to(None), Program.to(None)),
2619
+ )
2620
+ ).transaction
2621
+ transaction_id = tx.name
2622
+ spend_bundle = tx.spend_bundle
2623
+ assert spend_bundle is not None
2624
+
2625
+ await time_out_assert(20, tx_in_mempool, True, client, transaction_id)
2626
+ await farm_transaction(full_node_api, wallet_node, spend_bundle)
2627
+
2628
+ await time_out_assert(20, get_confirmed_balance, 0, client, cat_wallet_id)
2629
+
2630
+
2631
+ @pytest.mark.anyio
2632
+ async def test_get_balances(wallet_rpc_environment: WalletRpcTestEnvironment):
2633
+ env: WalletRpcTestEnvironment = wallet_rpc_environment
2634
+
2635
+ client: WalletRpcClient = env.wallet_1.rpc_client
2636
+ wallet_node: WalletNode = env.wallet_1.node
2637
+
2638
+ full_node_api: FullNodeSimulator = env.full_node.api
2639
+
2640
+ await generate_funds(full_node_api, env.wallet_1, 1)
2641
+
2642
+ await time_out_assert(20, check_client_synced, True, client)
2643
+ # Creates a CAT wallet with 100 mojos and a CAT with 20 mojos
2644
+ await client.create_new_cat_and_wallet(uint64(100), test=True)
2645
+
2646
+ await time_out_assert(20, check_client_synced, True, client)
2647
+ res = await client.create_new_cat_and_wallet(uint64(20), test=True)
2648
+ assert res["success"]
2649
+ await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 2)
2650
+ await farm_transaction_block(full_node_api, wallet_node)
2651
+ await time_out_assert(20, check_client_synced, True, client)
2652
+ bal = await client.get_wallet_balances()
2653
+ assert len(bal) == 3
2654
+ assert bal["1"]["confirmed_wallet_balance"] == 1999999999880
2655
+ assert bal["2"]["confirmed_wallet_balance"] == 100
2656
+ assert bal["3"]["confirmed_wallet_balance"] == 20
2657
+ bal_ids = await client.get_wallet_balances([3, 2])
2658
+ assert len(bal_ids) == 2
2659
+ assert bal["2"]["confirmed_wallet_balance"] == 100
2660
+ assert bal["3"]["confirmed_wallet_balance"] == 20
2661
+
2662
+
2663
+ @pytest.mark.parametrize(
2664
+ "wallet_environments",
2665
+ [
2666
+ {
2667
+ "num_environments": 1,
2668
+ "blocks_needed": [1],
2669
+ }
2670
+ ],
2671
+ indirect=True,
2672
+ )
2673
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2674
+ @pytest.mark.anyio
2675
+ async def test_split_coins(wallet_environments: WalletTestFramework, capsys: pytest.CaptureFixture[str]) -> None:
2676
+ env = wallet_environments.environments[0]
2677
+ env.wallet_aliases = {
2678
+ "xch": 1,
2679
+ "cat": 2,
2680
+ }
2681
+
2682
+ # Test XCH first
2683
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config) as action_scope:
2684
+ target_coin = next(iter(await env.xch_wallet.select_coins(uint64(250_000_000_000), action_scope)))
2685
+ assert target_coin.amount == 250_000_000_000
2686
+
2687
+ xch_request = SplitCMD(
2688
+ **{
2689
+ **wallet_environments.cmd_tx_endpoint_args(env),
2690
+ **dict(
2691
+ id=env.wallet_aliases["xch"],
2692
+ number_of_coins=100,
2693
+ amount_per_coin=CliAmount(amount=uint64(100), mojos=True),
2694
+ target_coin_id=target_coin.name(),
2695
+ fee=uint64(1_000_000_000_000), # 1 XCH
2696
+ push=True,
2697
+ ),
2698
+ }
2699
+ )
2700
+
2701
+ with pytest.raises(ResponseFailureError, match="501 coins is greater then the maximum limit of 500 coins"):
2702
+ await dataclasses.replace(xch_request, number_of_coins=501).run()
2703
+
2704
+ with pytest.raises(ResponseFailureError, match="Could not find coin with ID 00000000000000000"):
2705
+ await dataclasses.replace(xch_request, target_coin_id=bytes32.zeros).run()
2706
+
2707
+ with pytest.raises(ResponseFailureError, match="is less than the total amount of the split"):
2708
+ await dataclasses.replace(
2709
+ xch_request, amount_per_coin=CliAmount(amount=uint64(1_000_000_000_000), mojos=True)
2710
+ ).run()
2711
+
2712
+ # We catch this one
2713
+ capsys.readouterr()
2714
+ await dataclasses.replace(xch_request, id=50).run()
2715
+ output = (capsys.readouterr()).out
2716
+ assert "Wallet id: 50 not found" in output
2717
+
2718
+ # This one only "works" on the RPC
2719
+ env.wallet_state_manager.wallets[uint32(42)] = object() # type: ignore[assignment]
2720
+ with pytest.raises(ResponseFailureError, match="Cannot split coins from non-fungible wallet types"):
2721
+ assert xch_request.amount_per_coin is not None # hey there mypy
2722
+ rpc_request = SplitCoins(
2723
+ wallet_id=uint32(42),
2724
+ number_of_coins=uint16(xch_request.number_of_coins),
2725
+ amount_per_coin=xch_request.amount_per_coin.convert_amount(1),
2726
+ target_coin_id=xch_request.target_coin_id,
2727
+ fee=xch_request.fee,
2728
+ push=xch_request.push,
2729
+ )
2730
+ await env.rpc_client.split_coins(rpc_request, wallet_environments.tx_config)
2731
+
2732
+ del env.wallet_state_manager.wallets[uint32(42)]
2733
+
2734
+ await dataclasses.replace(xch_request, number_of_coins=0).run()
2735
+ output = (capsys.readouterr()).out
2736
+ assert "Transaction sent" not in output
2737
+
2738
+ with wallet_environments.new_puzzle_hashes_allowed():
2739
+ await xch_request.run()
2740
+
2741
+ await wallet_environments.process_pending_states(
2742
+ [
2743
+ WalletStateTransition(
2744
+ pre_block_balance_updates={
2745
+ "xch": {
2746
+ "unconfirmed_wallet_balance": -1_000_000_000_000, # just the fee
2747
+ "spendable_balance": -2_000_000_000_000,
2748
+ "pending_change": 1_000_000_000_000,
2749
+ "max_send_amount": -2_000_000_000_000,
2750
+ "pending_coin_removal_count": 2,
2751
+ }
2752
+ },
2753
+ post_block_balance_updates={
2754
+ "xch": {
2755
+ "confirmed_wallet_balance": -1_000_000_000_000, # just the fee
2756
+ "spendable_balance": 1_000_000_000_000,
2757
+ "pending_change": -1_000_000_000_000,
2758
+ "max_send_amount": 1_000_000_000_000,
2759
+ "pending_coin_removal_count": -2,
2760
+ "unspent_coin_count": 99, # split 1 into 100 i.e. +99
2761
+ }
2762
+ },
2763
+ )
2764
+ ]
2765
+ )
2766
+
2767
+ # Now do CATs
2768
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2769
+ cat_wallet = await CATWallet.create_new_cat_wallet(
2770
+ env.wallet_state_manager,
2771
+ env.xch_wallet,
2772
+ {"identifier": "genesis_by_id"},
2773
+ uint64(50),
2774
+ action_scope,
2775
+ )
2776
+
2777
+ await wallet_environments.process_pending_states(
2778
+ [
2779
+ WalletStateTransition(
2780
+ # no need to test this, it is tested elsewhere
2781
+ pre_block_balance_updates={
2782
+ "xch": {"set_remainder": True},
2783
+ "cat": {"init": True, "set_remainder": True},
2784
+ },
2785
+ post_block_balance_updates={
2786
+ "xch": {"set_remainder": True},
2787
+ "cat": {"set_remainder": True},
2788
+ },
2789
+ )
2790
+ ]
2791
+ )
2792
+
2793
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config) as action_scope:
2794
+ target_coin = next(iter(await cat_wallet.select_coins(uint64(50), action_scope)))
2795
+ assert target_coin.amount == 50
2796
+
2797
+ cat_request = SplitCMD(
2798
+ **{
2799
+ **wallet_environments.cmd_tx_endpoint_args(env),
2800
+ **dict(
2801
+ id=env.wallet_aliases["cat"],
2802
+ number_of_coins=50,
2803
+ amount_per_coin=CliAmount(amount=uint64(1), mojos=True),
2804
+ target_coin_id=target_coin.name(),
2805
+ push=True,
2806
+ ),
2807
+ }
2808
+ )
2809
+
2810
+ with wallet_environments.new_puzzle_hashes_allowed():
2811
+ await dataclasses.replace(cat_request).run()
2812
+
2813
+ await wallet_environments.process_pending_states(
2814
+ [
2815
+ WalletStateTransition(
2816
+ pre_block_balance_updates={
2817
+ "cat": {
2818
+ "unconfirmed_wallet_balance": 0,
2819
+ "spendable_balance": -50,
2820
+ "pending_change": 50,
2821
+ "max_send_amount": -50,
2822
+ "pending_coin_removal_count": 1,
2823
+ }
2824
+ },
2825
+ post_block_balance_updates={
2826
+ "cat": {
2827
+ "confirmed_wallet_balance": 0,
2828
+ "spendable_balance": 50,
2829
+ "pending_change": -50,
2830
+ "max_send_amount": 50,
2831
+ "pending_coin_removal_count": -1,
2832
+ "unspent_coin_count": 49, # split 1 into 50 i.e. +49
2833
+ }
2834
+ },
2835
+ )
2836
+ ]
2837
+ )
2838
+
2839
+ # Test a not synced error
2840
+ assert xch_request.rpc_info.client_info is not None
2841
+
2842
+ async def not_synced() -> GetSyncStatusResponse:
2843
+ return GetSyncStatusResponse(False, False)
2844
+
2845
+ xch_request.rpc_info.client_info.client.get_sync_status = not_synced # type: ignore[method-assign]
2846
+ await xch_request.run()
2847
+ output = (capsys.readouterr()).out
2848
+ assert "Wallet not synced. Please wait." in output
2849
+
2850
+
2851
+ @pytest.mark.parametrize(
2852
+ "wallet_environments",
2853
+ [
2854
+ {
2855
+ "num_environments": 1,
2856
+ "blocks_needed": [2],
2857
+ }
2858
+ ],
2859
+ indirect=True,
2860
+ )
2861
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2862
+ @pytest.mark.anyio
2863
+ async def test_combine_coins(wallet_environments: WalletTestFramework, capsys: pytest.CaptureFixture[str]) -> None:
2864
+ env = wallet_environments.environments[0]
2865
+ env.wallet_aliases = {
2866
+ "xch": 1,
2867
+ "cat": 2,
2868
+ }
2869
+
2870
+ # Should have 4 coins, two 1.75 XCH, two 0.25 XCH
2871
+
2872
+ # Grab one of the 0.25 ones to specify
2873
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config) as action_scope:
2874
+ target_coin = next(iter(await env.xch_wallet.select_coins(uint64(250_000_000_000), action_scope)))
2875
+ assert target_coin.amount == 250_000_000_000
2876
+
2877
+ # These parameters will give us the maximum amount of behavior coverage
2878
+ # - More amount than the coin we specify
2879
+ # - Less amount than will have to be selected in order create it
2880
+ # - Higher # coins than necessary to create it
2881
+ fee = uint64(100)
2882
+ xch_combine_request = CombineCMD(
2883
+ **{
2884
+ **wallet_environments.cmd_tx_endpoint_args(env),
2885
+ **dict(
2886
+ id=env.wallet_aliases["xch"],
2887
+ target_amount=CliAmount(amount=uint64(1_000_000_000_000), mojos=True),
2888
+ number_of_coins=uint16(3),
2889
+ input_coins=(target_coin.name(),),
2890
+ fee=fee,
2891
+ push=True,
2892
+ ),
2893
+ }
2894
+ )
2895
+
2896
+ # Test some error cases first
2897
+ with pytest.raises(ResponseFailureError, match="greater then the maximum limit"):
2898
+ await dataclasses.replace(xch_combine_request, number_of_coins=uint16(501)).run()
2899
+
2900
+ with pytest.raises(ResponseFailureError, match="You need at least two coins to combine"):
2901
+ await dataclasses.replace(xch_combine_request, number_of_coins=uint16(0)).run()
2902
+
2903
+ with pytest.raises(ResponseFailureError, match="More coin IDs specified than desired number of coins to combine"):
2904
+ await dataclasses.replace(xch_combine_request, input_coins=(bytes32.zeros,) * 100).run()
2905
+
2906
+ # We catch this one
2907
+ capsys.readouterr()
2908
+ await dataclasses.replace(xch_combine_request, id=50).run()
2909
+ output = (capsys.readouterr()).out
2910
+ assert "Wallet id: 50 not found" in output
2911
+
2912
+ # This one only "works" on the RPC
2913
+ env.wallet_state_manager.wallets[uint32(42)] = object() # type: ignore[assignment]
2914
+ with pytest.raises(ResponseFailureError, match="Cannot combine coins from non-fungible wallet types"):
2915
+ assert xch_combine_request.target_amount is not None # hey there mypy
2916
+ rpc_request = CombineCoins(
2917
+ wallet_id=uint32(42),
2918
+ target_coin_amount=xch_combine_request.target_amount.convert_amount(1),
2919
+ number_of_coins=uint16(xch_combine_request.number_of_coins),
2920
+ target_coin_ids=list(xch_combine_request.input_coins),
2921
+ fee=xch_combine_request.fee,
2922
+ push=xch_combine_request.push,
2923
+ )
2924
+ await env.rpc_client.combine_coins(rpc_request, wallet_environments.tx_config)
2925
+
2926
+ del env.wallet_state_manager.wallets[uint32(42)]
2927
+
2928
+ # Now push the request
2929
+ with patch("sys.stdin", new=io.StringIO("y\n")):
2930
+ await xch_combine_request.run()
2931
+
2932
+ await wallet_environments.process_pending_states(
2933
+ [
2934
+ WalletStateTransition(
2935
+ pre_block_balance_updates={
2936
+ "xch": {
2937
+ "unconfirmed_wallet_balance": -fee,
2938
+ "spendable_balance": -2_250_000_000_000,
2939
+ "pending_change": 2_250_000_000_000 - fee,
2940
+ "max_send_amount": -2_250_000_000_000,
2941
+ "pending_coin_removal_count": 3,
2942
+ }
2943
+ },
2944
+ post_block_balance_updates={
2945
+ "xch": {
2946
+ "confirmed_wallet_balance": -fee,
2947
+ "spendable_balance": 2_250_000_000_000 - fee,
2948
+ "pending_change": -(2_250_000_000_000 - fee),
2949
+ "max_send_amount": 2_250_000_000_000 - fee,
2950
+ "pending_coin_removal_count": -3,
2951
+ "unspent_coin_count": -1, # combine 3 into 1 + change
2952
+ }
2953
+ },
2954
+ )
2955
+ ]
2956
+ )
2957
+
2958
+ # Now do CATs
2959
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2960
+ cat_wallet = await CATWallet.create_new_cat_wallet(
2961
+ env.wallet_state_manager,
2962
+ env.xch_wallet,
2963
+ {"identifier": "genesis_by_id"},
2964
+ uint64(50),
2965
+ action_scope,
2966
+ )
2967
+
2968
+ await wallet_environments.process_pending_states(
2969
+ [
2970
+ WalletStateTransition(
2971
+ # no need to test this, it is tested elsewhere
2972
+ pre_block_balance_updates={
2973
+ "xch": {"set_remainder": True},
2974
+ "cat": {"init": True, "set_remainder": True},
2975
+ },
2976
+ post_block_balance_updates={
2977
+ "xch": {"set_remainder": True},
2978
+ "cat": {"set_remainder": True},
2979
+ },
2980
+ )
2981
+ ]
2982
+ )
2983
+
2984
+ BIG_COIN_AMOUNT = uint64(30)
2985
+ SMALL_COIN_AMOUNT = uint64(15)
2986
+ REALLY_SMALL_COIN_AMOUNT = uint64(5)
2987
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2988
+ await cat_wallet.generate_signed_transaction(
2989
+ [BIG_COIN_AMOUNT, SMALL_COIN_AMOUNT, REALLY_SMALL_COIN_AMOUNT],
2990
+ [await env.xch_wallet.get_puzzle_hash(new=not action_scope.config.tx_config.reuse_puzhash)] * 3,
2991
+ action_scope,
2992
+ )
2993
+
2994
+ await wallet_environments.process_pending_states(
2995
+ [
2996
+ WalletStateTransition(
2997
+ # no need to test this, it is tested elsewhere
2998
+ pre_block_balance_updates={
2999
+ "xch": {"set_remainder": True},
3000
+ "cat": {"init": True, "set_remainder": True},
3001
+ },
3002
+ post_block_balance_updates={
3003
+ "xch": {"set_remainder": True},
3004
+ "cat": {"set_remainder": True},
3005
+ },
3006
+ )
3007
+ ]
3008
+ )
3009
+
3010
+ # We're going to test that we select the two smaller coins
3011
+ cat_combine_request = CombineCMD(
3012
+ **{
3013
+ **wallet_environments.cmd_tx_endpoint_args(env),
3014
+ **dict(
3015
+ id=env.wallet_aliases["cat"],
3016
+ target_amount=None,
3017
+ number_of_coins=uint16(2),
3018
+ input_coins=(),
3019
+ largest_first=False,
3020
+ fee=fee,
3021
+ push=True,
3022
+ ),
3023
+ }
3024
+ )
3025
+
3026
+ with patch("sys.stdin", new=io.StringIO("y\n")):
3027
+ await cat_combine_request.run()
3028
+
3029
+ await wallet_environments.process_pending_states(
3030
+ [
3031
+ WalletStateTransition(
3032
+ pre_block_balance_updates={
3033
+ "xch": {
3034
+ "unconfirmed_wallet_balance": -fee,
3035
+ "set_remainder": True, # We only really care that a fee was in fact attached
3036
+ },
3037
+ "cat": {
3038
+ "spendable_balance": -SMALL_COIN_AMOUNT - REALLY_SMALL_COIN_AMOUNT,
3039
+ "pending_change": SMALL_COIN_AMOUNT + REALLY_SMALL_COIN_AMOUNT,
3040
+ "max_send_amount": -SMALL_COIN_AMOUNT - REALLY_SMALL_COIN_AMOUNT,
3041
+ "pending_coin_removal_count": 2,
3042
+ },
3043
+ },
3044
+ post_block_balance_updates={
3045
+ "xch": {
3046
+ "confirmed_wallet_balance": -fee,
3047
+ "set_remainder": True, # We only really care that a fee was in fact attached
3048
+ },
3049
+ "cat": {
3050
+ "spendable_balance": SMALL_COIN_AMOUNT + REALLY_SMALL_COIN_AMOUNT,
3051
+ "pending_change": -SMALL_COIN_AMOUNT - REALLY_SMALL_COIN_AMOUNT,
3052
+ "max_send_amount": SMALL_COIN_AMOUNT + REALLY_SMALL_COIN_AMOUNT,
3053
+ "pending_coin_removal_count": -2,
3054
+ "unspent_coin_count": -1,
3055
+ },
3056
+ },
3057
+ )
3058
+ ]
3059
+ )
3060
+
3061
+ # Test a not synced error
3062
+ assert xch_combine_request.rpc_info.client_info is not None
3063
+
3064
+ async def not_synced() -> GetSyncStatusResponse:
3065
+ return GetSyncStatusResponse(False, False)
3066
+
3067
+ xch_combine_request.rpc_info.client_info.client.get_sync_status = not_synced # type: ignore[method-assign]
3068
+ await xch_combine_request.run()
3069
+ output = (capsys.readouterr()).out
3070
+ assert "Wallet not synced. Please wait." in output
3071
+
3072
+
3073
+ @pytest.mark.parametrize(
3074
+ "wallet_environments",
3075
+ [
3076
+ {
3077
+ "num_environments": 1,
3078
+ "blocks_needed": [2],
3079
+ "trusted": True, # irrelevant
3080
+ "reuse_puzhash": True, # irrelevant
3081
+ }
3082
+ ],
3083
+ indirect=True,
3084
+ )
3085
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
3086
+ @pytest.mark.anyio
3087
+ async def test_fee_bigger_than_selection_coin_combining(wallet_environments: WalletTestFramework) -> None:
3088
+ """
3089
+ This tests the case where the coins we would otherwise select are not enough to pay the fee.
3090
+ """
3091
+
3092
+ env = wallet_environments.environments[0]
3093
+ env.wallet_aliases = {
3094
+ "xch": 1,
3095
+ "cat": 2,
3096
+ }
3097
+
3098
+ # Should have 4 coins, two 1.75 XCH, two 0.25 XCH
3099
+
3100
+ # Grab one of the 0.25 ones to specify
3101
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config) as action_scope:
3102
+ target_coin = next(iter(await env.xch_wallet.select_coins(uint64(250_000_000_000), action_scope)))
3103
+ assert target_coin.amount == 250_000_000_000
3104
+
3105
+ fee = uint64(1_750_000_000_000)
3106
+ # Under standard circumstances we would select the small coins, but this is not enough to pay the fee
3107
+ # Instead, we will grab the big coin first and combine it with one of the smaller coins
3108
+ xch_combine_request = CombineCMD(
3109
+ **{
3110
+ **wallet_environments.cmd_tx_endpoint_args(env),
3111
+ **dict(
3112
+ id=env.wallet_aliases["xch"],
3113
+ number_of_coins=uint16(2),
3114
+ input_coins=(),
3115
+ fee=fee,
3116
+ push=True,
3117
+ largest_first=False,
3118
+ ),
3119
+ }
3120
+ )
3121
+
3122
+ # First test an error where fee selection causes too many coins to be selected
3123
+ with pytest.raises(ResponseFailureError, match="without selecting more coins than specified: 3"):
3124
+ await dataclasses.replace(xch_combine_request, fee=uint64(2_250_000_000_000)).run()
3125
+
3126
+ with patch("sys.stdin", new=io.StringIO("y\n")):
3127
+ await xch_combine_request.run()
3128
+
3129
+ await wallet_environments.process_pending_states(
3130
+ [
3131
+ WalletStateTransition(
3132
+ pre_block_balance_updates={
3133
+ "xch": {
3134
+ "unconfirmed_wallet_balance": -fee,
3135
+ "spendable_balance": -2_000_000_000_000,
3136
+ "pending_change": 250_000_000_000,
3137
+ "max_send_amount": -2_000_000_000_000,
3138
+ "pending_coin_removal_count": 2,
3139
+ }
3140
+ },
3141
+ post_block_balance_updates={
3142
+ "xch": {
3143
+ "confirmed_wallet_balance": -fee,
3144
+ "spendable_balance": 250_000_000_000,
3145
+ "pending_change": -250_000_000_000,
3146
+ "max_send_amount": 250_000_000_000,
3147
+ "pending_coin_removal_count": -2,
3148
+ "unspent_coin_count": -1, # combine 2 into 1
3149
+ }
3150
+ },
3151
+ )
3152
+ ]
3153
+ )