chia-blockchain 2.5.7rc4__py3-none-any.whl → 2.5.8rc1__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 (528) hide show
  1. chia/__init__.py +8 -4
  2. chia/_tests/blockchain/blockchain_test_utils.py +6 -8
  3. chia/_tests/blockchain/test_augmented_chain.py +4 -4
  4. chia/_tests/blockchain/test_blockchain.py +165 -190
  5. chia/_tests/blockchain/test_build_chains.py +2 -4
  6. chia/_tests/blockchain/test_get_block_generator.py +2 -3
  7. chia/_tests/clvm/coin_store.py +4 -7
  8. chia/_tests/clvm/test_clvm_step.py +4 -4
  9. chia/_tests/clvm/test_puzzle_compression.py +2 -1
  10. chia/_tests/clvm/test_puzzle_drivers.py +2 -2
  11. chia/_tests/clvm/test_singletons.py +2 -4
  12. chia/_tests/clvm/test_spend_sim.py +2 -2
  13. chia/_tests/cmds/cmd_test_utils.py +27 -45
  14. chia/_tests/cmds/test_cmd_framework.py +6 -6
  15. chia/_tests/cmds/test_daemon.py +3 -3
  16. chia/_tests/cmds/test_show.py +4 -4
  17. chia/_tests/cmds/test_tx_config_args.py +1 -2
  18. chia/_tests/cmds/testing_classes.py +4 -5
  19. chia/_tests/cmds/wallet/test_did.py +24 -27
  20. chia/_tests/cmds/wallet/test_nft.py +12 -10
  21. chia/_tests/cmds/wallet/test_vcs.py +11 -12
  22. chia/_tests/cmds/wallet/test_wallet.py +134 -89
  23. chia/_tests/conftest.py +59 -30
  24. chia/_tests/connection_utils.py +2 -2
  25. chia/_tests/core/cmds/test_beta.py +4 -4
  26. chia/_tests/core/cmds/test_keys.py +2 -3
  27. chia/_tests/core/cmds/test_wallet.py +15 -15
  28. chia/_tests/core/consensus/test_pot_iterations.py +19 -73
  29. chia/_tests/core/custom_types/test_proof_of_space.py +124 -98
  30. chia/_tests/core/daemon/test_daemon.py +11 -11
  31. chia/_tests/core/data_layer/conftest.py +2 -2
  32. chia/_tests/core/data_layer/test_data_rpc.py +28 -14
  33. chia/_tests/core/data_layer/test_data_store.py +10 -10
  34. chia/_tests/core/data_layer/util.py +11 -11
  35. chia/_tests/core/farmer/test_farmer_api.py +2 -4
  36. chia/_tests/core/full_node/full_sync/test_full_sync.py +8 -7
  37. chia/_tests/core/full_node/stores/test_block_store.py +5 -4
  38. chia/_tests/core/full_node/stores/test_coin_store.py +5 -11
  39. chia/_tests/core/full_node/stores/test_full_node_store.py +8 -8
  40. chia/_tests/core/full_node/stores/test_hint_store.py +2 -2
  41. chia/_tests/core/full_node/test_block_height_map.py +3 -4
  42. chia/_tests/core/full_node/test_conditions.py +21 -23
  43. chia/_tests/core/full_node/test_full_node.py +225 -62
  44. chia/_tests/core/full_node/test_hint_management.py +2 -4
  45. chia/_tests/core/full_node/test_performance.py +0 -1
  46. chia/_tests/core/full_node/test_prev_tx_block.py +88 -11
  47. chia/_tests/core/full_node/test_transactions.py +1 -2
  48. chia/_tests/core/full_node/test_tx_processing_queue.py +109 -25
  49. chia/_tests/core/mempool/test_mempool.py +29 -37
  50. chia/_tests/core/mempool/test_mempool_fee_estimator.py +39 -39
  51. chia/_tests/core/mempool/test_mempool_fee_protocol.py +2 -6
  52. chia/_tests/core/mempool/test_mempool_manager.py +963 -839
  53. chia/_tests/core/mempool/test_singleton_fast_forward.py +6 -6
  54. chia/_tests/core/server/serve.py +7 -7
  55. chia/_tests/core/server/test_dos.py +1 -2
  56. chia/_tests/core/server/test_event_loop.py +12 -4
  57. chia/_tests/core/server/test_loop.py +7 -8
  58. chia/_tests/core/server/test_rate_limits.py +9 -8
  59. chia/_tests/core/server/test_server.py +61 -1
  60. chia/_tests/core/services/test_services.py +2 -2
  61. chia/_tests/core/ssl/test_ssl.py +2 -2
  62. chia/_tests/core/test_cost_calculation.py +2 -6
  63. chia/_tests/core/test_farmer_harvester_rpc.py +3 -5
  64. chia/_tests/core/test_filter.py +0 -1
  65. chia/_tests/core/test_full_node_rpc.py +2 -2
  66. chia/_tests/core/test_merkle_set.py +1 -2
  67. chia/_tests/core/test_seeder.py +4 -4
  68. chia/_tests/core/util/test_config.py +4 -4
  69. chia/_tests/core/util/test_jsonify.py +2 -2
  70. chia/_tests/core/util/test_keychain.py +3 -3
  71. chia/_tests/core/util/test_lockfile.py +2 -1
  72. chia/_tests/core/util/test_log_exceptions.py +1 -2
  73. chia/_tests/core/util/test_streamable.py +17 -17
  74. chia/_tests/db/test_db_wrapper.py +3 -2
  75. chia/_tests/environments/wallet.py +14 -14
  76. chia/_tests/ether.py +4 -3
  77. chia/_tests/farmer_harvester/test_farmer.py +41 -24
  78. chia/_tests/farmer_harvester/test_farmer_harvester.py +50 -17
  79. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +27 -27
  80. chia/_tests/farmer_harvester/test_third_party_harvesters.py +21 -22
  81. chia/_tests/fee_estimation/test_fee_estimation_integration.py +18 -18
  82. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +11 -9
  83. chia/_tests/harvester/test_harvester_api.py +11 -4
  84. chia/_tests/plot_sync/test_plot_sync.py +13 -11
  85. chia/_tests/plot_sync/test_receiver.py +11 -10
  86. chia/_tests/plot_sync/test_sync_simulated.py +2 -2
  87. chia/_tests/plot_sync/util.py +1 -2
  88. chia/_tests/plotting/test_plot_manager.py +7 -6
  89. chia/_tests/plotting/test_prover.py +30 -38
  90. chia/_tests/pools/test_pool_cmdline.py +4 -6
  91. chia/_tests/pools/test_pool_rpc.py +203 -61
  92. chia/_tests/pools/test_pool_wallet.py +3 -3
  93. chia/_tests/pools/test_wallet_pool_store.py +1 -4
  94. chia/_tests/process_junit.py +2 -2
  95. chia/_tests/rpc/test_rpc_client.py +4 -4
  96. chia/_tests/rpc/test_rpc_server.py +3 -3
  97. chia/_tests/simulation/test_simulation.py +12 -25
  98. chia/_tests/solver/test_solver_service.py +13 -4
  99. chia/_tests/testconfig.py +2 -2
  100. chia/_tests/timelord/test_new_peak.py +22 -11
  101. chia/_tests/tools/test_run_block.py +0 -2
  102. chia/_tests/tools/test_virtual_project.py +2 -1
  103. chia/_tests/util/benchmarks.py +1 -0
  104. chia/_tests/util/blockchain.py +38 -36
  105. chia/_tests/util/blockchain_mock.py +11 -11
  106. chia/_tests/util/build_network_protocol_files.py +2 -1
  107. chia/_tests/util/coin_store.py +2 -1
  108. chia/_tests/util/config.py +1 -1
  109. chia/_tests/util/db_connection.py +2 -3
  110. chia/_tests/util/full_sync.py +9 -11
  111. chia/_tests/util/gen_ssl_certs.py +4 -5
  112. chia/_tests/util/get_name_puzzle_conditions.py +2 -0
  113. chia/_tests/util/misc.py +24 -24
  114. chia/_tests/util/network_protocol_data.py +20 -3
  115. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  116. chia/_tests/util/protocol_messages_json.py +292 -3
  117. chia/_tests/util/setup_nodes.py +62 -47
  118. chia/_tests/util/spend_sim.py +57 -57
  119. chia/_tests/util/test_async_pool.py +2 -3
  120. chia/_tests/util/test_chia_version.py +1 -3
  121. chia/_tests/util/test_config.py +3 -3
  122. chia/_tests/util/test_full_block_utils.py +6 -3
  123. chia/_tests/util/test_limited_semaphore.py +1 -2
  124. chia/_tests/util/test_misc.py +2 -2
  125. chia/_tests/util/test_network.py +1 -2
  126. chia/_tests/util/test_priority_mutex.py +3 -3
  127. chia/_tests/util/test_recursive_replace.py +5 -6
  128. chia/_tests/util/test_replace_str_to_bytes.py +8 -10
  129. chia/_tests/util/test_testnet_overrides.py +3 -3
  130. chia/_tests/util/time_out_assert.py +2 -2
  131. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +4 -6
  132. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +2 -4
  133. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +19 -13
  134. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +13 -13
  135. chia/_tests/wallet/cat_wallet/test_trades.py +40 -38
  136. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +2 -4
  137. chia/_tests/wallet/conftest.py +6 -6
  138. chia/_tests/wallet/db_wallet/test_db_graftroot.py +1 -1
  139. chia/_tests/wallet/db_wallet/test_dl_offers.py +34 -34
  140. chia/_tests/wallet/did_wallet/test_did.py +16 -6
  141. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +21 -21
  142. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +20 -6
  143. chia/_tests/wallet/nft_wallet/test_nft_offers.py +19 -21
  144. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +1 -2
  145. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +121 -2
  146. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +6 -9
  147. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +44 -1
  148. chia/_tests/wallet/rpc/test_wallet_rpc.py +1672 -896
  149. chia/_tests/wallet/sync/test_wallet_sync.py +43 -47
  150. chia/_tests/wallet/test_clvm_streamable.py +2 -3
  151. chia/_tests/wallet/test_coin_management.py +2 -2
  152. chia/_tests/wallet/test_conditions.py +45 -51
  153. chia/_tests/wallet/test_debug_spend_bundle.py +2 -2
  154. chia/_tests/wallet/test_new_wallet_protocol.py +4 -6
  155. chia/_tests/wallet/test_notifications.py +14 -14
  156. chia/_tests/wallet/test_signer_protocol.py +5 -5
  157. chia/_tests/wallet/test_singleton_lifecycle_fast.py +4 -3
  158. chia/_tests/wallet/test_transaction_store.py +20 -20
  159. chia/_tests/wallet/test_util.py +2 -2
  160. chia/_tests/wallet/test_wallet.py +380 -228
  161. chia/_tests/wallet/test_wallet_action_scope.py +4 -4
  162. chia/_tests/wallet/test_wallet_blockchain.py +12 -12
  163. chia/_tests/wallet/test_wallet_coin_store.py +3 -4
  164. chia/_tests/wallet/test_wallet_node.py +14 -14
  165. chia/_tests/wallet/test_wallet_test_framework.py +2 -1
  166. chia/_tests/wallet/test_wallet_utils.py +2 -3
  167. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +3 -5
  168. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +14 -15
  169. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +29 -24
  170. chia/_tests/wallet/wallet_block_tools.py +12 -11
  171. chia/_tests/weight_proof/config.py +1 -0
  172. chia/_tests/weight_proof/test_weight_proof.py +5 -4
  173. chia/apis/__init__.py +21 -0
  174. chia/apis/farmer_stub.py +102 -0
  175. chia/apis/full_node_stub.py +372 -0
  176. chia/apis/harvester_stub.py +57 -0
  177. chia/apis/introducer_stub.py +35 -0
  178. chia/apis/solver_stub.py +30 -0
  179. chia/apis/stub_protocol_registry.py +21 -0
  180. chia/apis/timelord_stub.py +39 -0
  181. chia/apis/wallet_stub.py +161 -0
  182. chia/cmds/beta.py +3 -4
  183. chia/cmds/beta_funcs.py +4 -3
  184. chia/cmds/check_wallet_db.py +4 -4
  185. chia/cmds/chia.py +1 -2
  186. chia/cmds/cmd_classes.py +11 -13
  187. chia/cmds/cmd_helpers.py +11 -11
  188. chia/cmds/cmds_util.py +15 -15
  189. chia/cmds/coin_funcs.py +6 -7
  190. chia/cmds/coins.py +2 -3
  191. chia/cmds/configure.py +1 -2
  192. chia/cmds/data.py +42 -42
  193. chia/cmds/data_funcs.py +81 -81
  194. chia/cmds/db.py +4 -5
  195. chia/cmds/db_backup_func.py +2 -2
  196. chia/cmds/db_upgrade_func.py +3 -3
  197. chia/cmds/db_validate_func.py +2 -2
  198. chia/cmds/dev/data.py +4 -4
  199. chia/cmds/dev/gh.py +5 -5
  200. chia/cmds/dev/installers.py +2 -3
  201. chia/cmds/dev/mempool.py +3 -4
  202. chia/cmds/dev/mempool_funcs.py +4 -4
  203. chia/cmds/dev/sim.py +8 -8
  204. chia/cmds/dump_keyring.py +3 -3
  205. chia/cmds/farm.py +6 -8
  206. chia/cmds/farm_funcs.py +25 -24
  207. chia/cmds/init_funcs.py +4 -4
  208. chia/cmds/keys.py +16 -18
  209. chia/cmds/keys_funcs.py +36 -36
  210. chia/cmds/netspace.py +1 -3
  211. chia/cmds/netspace_funcs.py +1 -2
  212. chia/cmds/options.py +3 -2
  213. chia/cmds/param_types.py +17 -16
  214. chia/cmds/passphrase.py +6 -7
  215. chia/cmds/passphrase_funcs.py +11 -13
  216. chia/cmds/peer.py +1 -3
  217. chia/cmds/peer_funcs.py +3 -3
  218. chia/cmds/plotnft.py +6 -7
  219. chia/cmds/plotnft_funcs.py +37 -26
  220. chia/cmds/rpc.py +3 -3
  221. chia/cmds/show.py +3 -5
  222. chia/cmds/show_funcs.py +9 -9
  223. chia/cmds/sim_funcs.py +25 -26
  224. chia/cmds/solver.py +1 -3
  225. chia/cmds/solver_funcs.py +1 -2
  226. chia/cmds/start_funcs.py +2 -2
  227. chia/cmds/wallet.py +76 -81
  228. chia/cmds/wallet_funcs.py +206 -177
  229. chia/consensus/augmented_chain.py +6 -6
  230. chia/consensus/block_body_validation.py +19 -15
  231. chia/consensus/block_creation.py +25 -21
  232. chia/consensus/block_header_validation.py +27 -13
  233. chia/consensus/block_height_map.py +3 -6
  234. chia/consensus/block_height_map_protocol.py +2 -2
  235. chia/consensus/block_record.py +2 -4
  236. chia/consensus/blockchain.py +58 -40
  237. chia/consensus/blockchain_interface.py +7 -7
  238. chia/consensus/coin_store_protocol.py +5 -6
  239. chia/consensus/condition_tools.py +4 -4
  240. chia/consensus/cost_calculator.py +2 -3
  241. chia/consensus/default_constants.py +16 -13
  242. chia/consensus/deficit.py +1 -3
  243. chia/consensus/difficulty_adjustment.py +3 -5
  244. chia/consensus/find_fork_point.py +2 -4
  245. chia/consensus/full_block_to_block_record.py +11 -13
  246. chia/consensus/generator_tools.py +2 -3
  247. chia/consensus/get_block_challenge.py +42 -26
  248. chia/consensus/get_block_generator.py +2 -3
  249. chia/consensus/make_sub_epoch_summary.py +8 -7
  250. chia/consensus/multiprocess_validation.py +31 -20
  251. chia/consensus/pos_quality.py +6 -23
  252. chia/consensus/pot_iterations.py +17 -44
  253. chia/consensus/signage_point.py +4 -5
  254. chia/consensus/vdf_info_computation.py +2 -4
  255. chia/daemon/client.py +8 -8
  256. chia/daemon/keychain_proxy.py +31 -37
  257. chia/daemon/server.py +32 -33
  258. chia/daemon/windows_signal.py +4 -3
  259. chia/data_layer/data_layer.py +86 -77
  260. chia/data_layer/data_layer_rpc_api.py +9 -9
  261. chia/data_layer/data_layer_rpc_client.py +13 -15
  262. chia/data_layer/data_layer_server.py +3 -3
  263. chia/data_layer/data_layer_util.py +14 -14
  264. chia/data_layer/data_layer_wallet.py +94 -101
  265. chia/data_layer/data_store.py +50 -50
  266. chia/data_layer/dl_wallet_store.py +9 -12
  267. chia/data_layer/download_data.py +8 -9
  268. chia/data_layer/s3_plugin_service.py +5 -9
  269. chia/data_layer/start_data_layer.py +5 -5
  270. chia/farmer/farmer.py +31 -31
  271. chia/farmer/farmer_api.py +45 -33
  272. chia/farmer/farmer_rpc_api.py +5 -4
  273. chia/farmer/farmer_rpc_client.py +6 -6
  274. chia/farmer/start_farmer.py +6 -6
  275. chia/full_node/block_store.py +13 -16
  276. chia/full_node/check_fork_next_block.py +1 -2
  277. chia/full_node/coin_store.py +15 -16
  278. chia/full_node/eligible_coin_spends.py +3 -3
  279. chia/full_node/fee_estimate_store.py +2 -3
  280. chia/full_node/fee_tracker.py +1 -2
  281. chia/full_node/full_block_utils.py +4 -4
  282. chia/full_node/full_node.py +238 -224
  283. chia/full_node/full_node_api.py +193 -150
  284. chia/full_node/full_node_rpc_api.py +53 -31
  285. chia/full_node/full_node_rpc_client.py +18 -19
  286. chia/full_node/full_node_store.py +45 -43
  287. chia/full_node/hint_management.py +2 -2
  288. chia/full_node/mempool.py +17 -19
  289. chia/full_node/mempool_manager.py +89 -42
  290. chia/full_node/pending_tx_cache.py +2 -3
  291. chia/full_node/start_full_node.py +5 -5
  292. chia/full_node/sync_store.py +3 -4
  293. chia/full_node/tx_processing_queue.py +34 -13
  294. chia/full_node/weight_proof.py +61 -48
  295. chia/harvester/harvester.py +25 -24
  296. chia/harvester/harvester_api.py +61 -38
  297. chia/harvester/harvester_rpc_api.py +10 -10
  298. chia/harvester/start_harvester.py +4 -4
  299. chia/introducer/introducer.py +3 -3
  300. chia/introducer/introducer_api.py +6 -4
  301. chia/introducer/start_introducer.py +4 -4
  302. chia/legacy/keyring.py +3 -3
  303. chia/plot_sync/delta.py +1 -2
  304. chia/plot_sync/receiver.py +20 -17
  305. chia/plot_sync/sender.py +15 -10
  306. chia/plotters/bladebit.py +7 -7
  307. chia/plotters/chiapos.py +2 -2
  308. chia/plotters/madmax.py +4 -4
  309. chia/plotters/plotters.py +4 -4
  310. chia/plotters/plotters_util.py +3 -3
  311. chia/plotting/cache.py +20 -14
  312. chia/plotting/check_plots.py +26 -35
  313. chia/plotting/create_plots.py +22 -23
  314. chia/plotting/manager.py +21 -14
  315. chia/plotting/prover.py +59 -42
  316. chia/plotting/util.py +16 -16
  317. chia/pools/pool_config.py +2 -1
  318. chia/pools/pool_puzzles.py +11 -12
  319. chia/pools/pool_wallet.py +34 -57
  320. chia/pools/pool_wallet_info.py +39 -10
  321. chia/protocols/farmer_protocol.py +8 -9
  322. chia/protocols/fee_estimate.py +3 -4
  323. chia/protocols/full_node_protocol.py +3 -4
  324. chia/protocols/harvester_protocol.py +27 -15
  325. chia/protocols/outbound_message.py +3 -3
  326. chia/protocols/pool_protocol.py +8 -9
  327. chia/protocols/shared_protocol.py +1 -2
  328. chia/protocols/solver_protocol.py +9 -2
  329. chia/protocols/timelord_protocol.py +4 -7
  330. chia/protocols/wallet_protocol.py +11 -12
  331. chia/rpc/rpc_client.py +9 -9
  332. chia/rpc/rpc_server.py +17 -17
  333. chia/rpc/util.py +2 -2
  334. chia/seeder/crawler.py +8 -8
  335. chia/seeder/crawler_api.py +21 -27
  336. chia/seeder/crawler_rpc_api.py +2 -2
  337. chia/seeder/dns_server.py +21 -21
  338. chia/seeder/start_crawler.py +4 -4
  339. chia/server/address_manager.py +15 -16
  340. chia/server/api_protocol.py +11 -11
  341. chia/server/chia_policy.py +46 -26
  342. chia/server/introducer_peers.py +2 -3
  343. chia/server/node_discovery.py +19 -19
  344. chia/server/rate_limit_numbers.py +4 -5
  345. chia/server/rate_limits.py +4 -4
  346. chia/server/resolve_peer_info.py +4 -4
  347. chia/server/server.py +49 -52
  348. chia/server/signal_handlers.py +6 -6
  349. chia/server/start_service.py +17 -17
  350. chia/server/upnp.py +4 -6
  351. chia/server/ws_connection.py +52 -37
  352. chia/simulator/add_blocks_in_batches.py +1 -3
  353. chia/simulator/block_tools.py +312 -200
  354. chia/simulator/full_node_simulator.py +56 -35
  355. chia/simulator/keyring.py +2 -3
  356. chia/simulator/setup_services.py +15 -15
  357. chia/simulator/simulator_full_node_rpc_api.py +1 -2
  358. chia/simulator/simulator_full_node_rpc_client.py +1 -2
  359. chia/simulator/simulator_protocol.py +1 -2
  360. chia/simulator/simulator_test_tools.py +3 -3
  361. chia/simulator/start_simulator.py +7 -7
  362. chia/simulator/wallet_tools.py +10 -10
  363. chia/solver/solver.py +10 -10
  364. chia/solver/solver_api.py +10 -8
  365. chia/solver/solver_rpc_api.py +2 -2
  366. chia/solver/start_solver.py +4 -4
  367. chia/ssl/cacert.pem +148 -90
  368. chia/ssl/chia_ca.crt +14 -10
  369. chia/ssl/chia_ca_old.crt +19 -0
  370. chia/ssl/create_ssl.py +4 -4
  371. chia/ssl/renewedselfsignedca.conf +4 -0
  372. chia/ssl/ssl_check.py +1 -2
  373. chia/timelord/iters_from_block.py +1 -4
  374. chia/timelord/start_timelord.py +4 -4
  375. chia/timelord/timelord.py +44 -40
  376. chia/timelord/timelord_api.py +6 -4
  377. chia/timelord/timelord_launcher.py +2 -2
  378. chia/timelord/timelord_rpc_api.py +2 -2
  379. chia/timelord/timelord_state.py +11 -12
  380. chia/types/block_protocol.py +1 -3
  381. chia/types/blockchain_format/coin.py +1 -3
  382. chia/types/blockchain_format/program.py +11 -8
  383. chia/types/blockchain_format/proof_of_space.py +123 -76
  384. chia/types/blockchain_format/tree_hash.py +3 -3
  385. chia/types/blockchain_format/vdf.py +1 -2
  386. chia/types/coin_spend.py +3 -3
  387. chia/types/mempool_item.py +5 -5
  388. chia/types/mempool_submission_status.py +2 -3
  389. chia/types/peer_info.py +1 -2
  390. chia/types/unfinished_header_block.py +3 -4
  391. chia/types/validation_state.py +1 -2
  392. chia/util/action_scope.py +8 -8
  393. chia/util/async_pool.py +5 -5
  394. chia/util/bech32m.py +1 -2
  395. chia/util/beta_metrics.py +2 -2
  396. chia/util/block_cache.py +4 -4
  397. chia/util/chia_logging.py +2 -2
  398. chia/util/chia_version.py +1 -2
  399. chia/util/config.py +15 -16
  400. chia/util/db_wrapper.py +26 -27
  401. chia/util/default_root.py +1 -2
  402. chia/util/errors.py +3 -3
  403. chia/util/file_keyring.py +14 -14
  404. chia/util/files.py +2 -3
  405. chia/util/hash.py +4 -4
  406. chia/util/initial-config.yaml +3 -5
  407. chia/util/inline_executor.py +2 -1
  408. chia/util/ip_address.py +1 -2
  409. chia/util/keychain.py +25 -27
  410. chia/util/keyring_wrapper.py +18 -19
  411. chia/util/lock.py +3 -4
  412. chia/util/log_exceptions.py +1 -2
  413. chia/util/lru_cache.py +2 -2
  414. chia/util/network.py +6 -6
  415. chia/util/path.py +2 -3
  416. chia/util/priority_mutex.py +2 -2
  417. chia/util/profiler.py +1 -2
  418. chia/util/safe_cancel_task.py +1 -2
  419. chia/util/streamable.py +22 -8
  420. chia/util/task_referencer.py +1 -1
  421. chia/util/timing.py +3 -3
  422. chia/util/virtual_project_analysis.py +6 -5
  423. chia/util/ws_message.py +2 -2
  424. chia/wallet/cat_wallet/cat_info.py +3 -4
  425. chia/wallet/cat_wallet/cat_outer_puzzle.py +12 -11
  426. chia/wallet/cat_wallet/cat_utils.py +3 -4
  427. chia/wallet/cat_wallet/cat_wallet.py +61 -83
  428. chia/wallet/cat_wallet/lineage_store.py +3 -4
  429. chia/wallet/cat_wallet/r_cat_wallet.py +19 -22
  430. chia/wallet/coin_selection.py +9 -10
  431. chia/wallet/conditions.py +120 -105
  432. chia/wallet/db_wallet/db_wallet_puzzles.py +4 -5
  433. chia/wallet/derivation_record.py +1 -2
  434. chia/wallet/derive_keys.py +2 -4
  435. chia/wallet/did_wallet/did_info.py +10 -11
  436. chia/wallet/did_wallet/did_wallet.py +36 -82
  437. chia/wallet/did_wallet/did_wallet_puzzles.py +7 -8
  438. chia/wallet/driver_protocol.py +5 -7
  439. chia/wallet/lineage_proof.py +4 -4
  440. chia/wallet/nft_wallet/metadata_outer_puzzle.py +11 -11
  441. chia/wallet/nft_wallet/nft_info.py +8 -9
  442. chia/wallet/nft_wallet/nft_puzzle_utils.py +8 -8
  443. chia/wallet/nft_wallet/nft_wallet.py +79 -116
  444. chia/wallet/nft_wallet/ownership_outer_puzzle.py +14 -14
  445. chia/wallet/nft_wallet/singleton_outer_puzzle.py +12 -11
  446. chia/wallet/nft_wallet/transfer_program_puzzle.py +11 -11
  447. chia/wallet/nft_wallet/uncurry_nft.py +10 -11
  448. chia/wallet/notification_manager.py +3 -3
  449. chia/wallet/notification_store.py +44 -61
  450. chia/wallet/outer_puzzles.py +6 -7
  451. chia/wallet/puzzle_drivers.py +34 -6
  452. chia/wallet/puzzles/clawback/drivers.py +6 -6
  453. chia/wallet/puzzles/deployed_puzzle_hashes.json +1 -54
  454. chia/wallet/puzzles/load_clvm.py +1 -1
  455. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +1 -2
  456. chia/wallet/puzzles/singleton_top_layer.py +2 -3
  457. chia/wallet/puzzles/singleton_top_layer_v1_1.py +3 -4
  458. chia/wallet/puzzles/tails.py +3 -3
  459. chia/wallet/singleton.py +5 -7
  460. chia/wallet/singleton_record.py +3 -3
  461. chia/wallet/start_wallet.py +5 -5
  462. chia/wallet/trade_manager.py +37 -58
  463. chia/wallet/trade_record.py +4 -4
  464. chia/wallet/trading/offer.py +59 -46
  465. chia/wallet/trading/trade_store.py +8 -9
  466. chia/wallet/transaction_record.py +8 -8
  467. chia/wallet/uncurried_puzzle.py +1 -2
  468. chia/wallet/util/clvm_streamable.py +12 -12
  469. chia/wallet/util/compute_hints.py +4 -5
  470. chia/wallet/util/curry_and_treehash.py +1 -2
  471. chia/wallet/util/merkle_tree.py +2 -3
  472. chia/wallet/util/peer_request_cache.py +8 -8
  473. chia/wallet/util/signing.py +85 -0
  474. chia/wallet/util/tx_config.py +15 -6
  475. chia/wallet/util/wallet_sync_utils.py +14 -16
  476. chia/wallet/util/wallet_types.py +2 -2
  477. chia/wallet/vc_wallet/cr_cat_drivers.py +10 -11
  478. chia/wallet/vc_wallet/cr_cat_wallet.py +50 -68
  479. chia/wallet/vc_wallet/cr_outer_puzzle.py +14 -13
  480. chia/wallet/vc_wallet/vc_drivers.py +27 -27
  481. chia/wallet/vc_wallet/vc_store.py +5 -6
  482. chia/wallet/vc_wallet/vc_wallet.py +33 -61
  483. chia/wallet/wallet.py +50 -78
  484. chia/wallet/wallet_action_scope.py +11 -11
  485. chia/wallet/wallet_blockchain.py +12 -12
  486. chia/wallet/wallet_coin_record.py +12 -6
  487. chia/wallet/wallet_coin_store.py +24 -25
  488. chia/wallet/wallet_interested_store.py +3 -5
  489. chia/wallet/wallet_nft_store.py +10 -11
  490. chia/wallet/wallet_node.py +53 -61
  491. chia/wallet/wallet_node_api.py +5 -3
  492. chia/wallet/wallet_protocol.py +23 -23
  493. chia/wallet/wallet_puzzle_store.py +15 -18
  494. chia/wallet/wallet_request_types.py +778 -114
  495. chia/wallet/wallet_retry_store.py +1 -3
  496. chia/wallet/wallet_rpc_api.py +572 -909
  497. chia/wallet/wallet_rpc_client.py +87 -279
  498. chia/wallet/wallet_singleton_store.py +3 -4
  499. chia/wallet/wallet_state_manager.py +332 -106
  500. chia/wallet/wallet_transaction_store.py +11 -14
  501. chia/wallet/wallet_user_store.py +4 -6
  502. chia/wallet/wallet_weight_proof_handler.py +4 -4
  503. {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/METADATA +6 -5
  504. {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/RECORD +507 -516
  505. chia/apis.py +0 -21
  506. chia/consensus/check_time_locks.py +0 -57
  507. chia/data_layer/puzzles/__init__.py +0 -0
  508. chia/data_layer/puzzles/graftroot_dl_offers.clsp +0 -100
  509. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +0 -1
  510. chia/types/coin_record.py +0 -44
  511. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  512. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +0 -6
  513. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +0 -1
  514. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +0 -6
  515. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +0 -1
  516. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +0 -30
  517. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +0 -1
  518. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +0 -28
  519. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +0 -1
  520. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +0 -100
  521. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +0 -1
  522. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +0 -78
  523. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +0 -1
  524. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +0 -74
  525. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +0 -1
  526. {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/WHEEL +0 -0
  527. {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/entry_points.txt +0 -0
  528. {chia_blockchain-2.5.7rc4.dist-info → chia_blockchain-2.5.8rc1.dist-info}/licenses/LICENSE +0 -0
@@ -1,26 +1,22 @@
1
1
  from __future__ import annotations
2
2
 
3
- import asyncio
4
3
  import dataclasses
5
4
  import io
6
5
  import json
7
6
  import logging
8
- import random
9
7
  import re
10
- from collections.abc import AsyncIterator
11
8
  from operator import attrgetter
12
- from typing import Any, Optional
9
+ from typing import Any
13
10
  from unittest.mock import patch
14
11
 
15
12
  import aiosqlite
16
13
  import pytest
17
- from chia_rs import CoinSpend, G1Element, G2Element
14
+ from chia_rs import CoinRecord, CoinSpend, G1Element, G2Element
18
15
  from chia_rs.sized_bytes import bytes32
19
16
  from chia_rs.sized_ints import uint16, uint32, uint64, uint128
20
17
 
21
18
  from chia._tests.environments.wallet import WalletStateTransition, WalletTestFramework
22
- from chia._tests.util.setup_nodes import SimulatorsAndWalletsServices
23
- from chia._tests.util.time_out_assert import time_out_assert, time_out_assert_not_none
19
+ from chia._tests.util.time_out_assert import time_out_assert
24
20
  from chia._tests.wallet.cat_wallet.test_cat_wallet import mint_cat
25
21
  from chia._tests.wallet.test_wallet_coin_store import (
26
22
  get_coin_records_amount_filter_tests,
@@ -50,29 +46,25 @@ from chia._tests.wallet.test_wallet_coin_store import (
50
46
  )
51
47
  from chia.cmds.coins import CombineCMD, SplitCMD
52
48
  from chia.cmds.param_types import CliAmount
53
- from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
54
49
  from chia.full_node.full_node_rpc_client import FullNodeRpcClient
50
+ from chia.pools.pool_wallet_info import NewPoolWalletInitialTargetState
55
51
  from chia.rpc.rpc_client import ResponseFailureError
56
- from chia.server.server import ChiaServer
57
52
  from chia.simulator.full_node_simulator import FullNodeSimulator
58
- from chia.simulator.simulator_protocol import FarmNewBlockProtocol
59
53
  from chia.types.blockchain_format.coin import Coin, coin_as_list
60
54
  from chia.types.blockchain_format.program import Program
61
- from chia.types.coin_record import CoinRecord
62
55
  from chia.types.coin_spend import make_spend
63
- from chia.types.peer_info import PeerInfo
64
56
  from chia.types.signing_mode import SigningMode
65
57
  from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
66
58
  from chia.util.config import load_config, lock_and_load_config, save_config
67
59
  from chia.util.db_wrapper import DBWrapper2
68
60
  from chia.util.hash import std_hash
69
- from chia.util.streamable import ConversionError, InvalidTypeError
70
61
  from chia.wallet.cat_wallet.cat_constants import DEFAULT_CATS
71
62
  from chia.wallet.cat_wallet.cat_utils import CAT_MOD, construct_cat_puzzle
72
63
  from chia.wallet.cat_wallet.cat_wallet import CATWallet
73
64
  from chia.wallet.cat_wallet.r_cat_wallet import RCATWallet
74
65
  from chia.wallet.conditions import (
75
66
  ConditionValidTimes,
67
+ ConditionValidTimesAbsolute,
76
68
  CreateCoinAnnouncement,
77
69
  CreatePuzzleAnnouncement,
78
70
  Remark,
@@ -81,11 +73,11 @@ from chia.wallet.conditions import (
81
73
  from chia.wallet.derive_keys import master_sk_to_wallet_sk, master_sk_to_wallet_sk_unhardened
82
74
  from chia.wallet.did_wallet.did_wallet import DIDWallet
83
75
  from chia.wallet.nft_wallet.nft_wallet import NFTWallet
84
- from chia.wallet.puzzles.clawback.metadata import AutoClaimSettings
76
+ from chia.wallet.puzzle_drivers import PuzzleInfo
85
77
  from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import puzzle_hash_for_pk
86
78
  from chia.wallet.signer_protocol import UnsignedTransaction
87
79
  from chia.wallet.trade_record import TradeRecord
88
- from chia.wallet.trading.offer import Offer
80
+ from chia.wallet.trading.offer import Offer, OfferSummary
89
81
  from chia.wallet.trading.trade_status import TradeStatus
90
82
  from chia.wallet.transaction_record import TransactionRecord
91
83
  from chia.wallet.transaction_sorting import SortKey
@@ -96,15 +88,18 @@ from chia.wallet.util.clvm_streamable import byte_deserialize_clvm_streamable
96
88
  from chia.wallet.util.compute_memos import compute_memos
97
89
  from chia.wallet.util.query_filter import AmountFilter, HashFilter, TransactionTypeFilter
98
90
  from chia.wallet.util.transaction_type import TransactionType
99
- from chia.wallet.util.tx_config import DEFAULT_COIN_SELECTION_CONFIG, DEFAULT_TX_CONFIG
91
+ from chia.wallet.util.tx_config import TXConfig
100
92
  from chia.wallet.util.wallet_types import CoinType, WalletType
101
93
  from chia.wallet.wallet import Wallet
102
94
  from chia.wallet.wallet_coin_record import WalletCoinRecord
103
95
  from chia.wallet.wallet_coin_store import GetCoinRecords
104
- from chia.wallet.wallet_node import WalletNode
96
+ from chia.wallet.wallet_node import WalletNode, get_wallet_db_path
105
97
  from chia.wallet.wallet_protocol import WalletProtocol
106
98
  from chia.wallet.wallet_request_types import (
99
+ Addition,
107
100
  AddKey,
101
+ CancelOffer,
102
+ CancelOffers,
108
103
  CATAssetIDToName,
109
104
  CATGetAssetID,
110
105
  CATGetName,
@@ -114,6 +109,10 @@ from chia.wallet.wallet_request_types import (
114
109
  CheckOfferValidity,
115
110
  ClawbackPuzzleDecoratorOverride,
116
111
  CombineCoins,
112
+ CreateNewWallet,
113
+ CreateNewWalletType,
114
+ CreateOfferForIDs,
115
+ CreateSignedTransaction,
117
116
  DefaultCAT,
118
117
  DeleteKey,
119
118
  DeleteNotifications,
@@ -126,11 +125,17 @@ from chia.wallet.wallet_request_types import (
126
125
  DIDMessageSpend,
127
126
  DIDSetWalletName,
128
127
  DIDTransferDID,
128
+ DIDType,
129
129
  DIDUpdateMetadata,
130
130
  FungibleAsset,
131
+ GetAllOffers,
131
132
  GetCoinRecordsByNames,
133
+ GetFarmedAmount,
134
+ GetFarmedAmountResponse,
132
135
  GetNextAddress,
133
136
  GetNotifications,
137
+ GetOffer,
138
+ GetOfferSummary,
134
139
  GetPrivateKey,
135
140
  GetSpendableCoins,
136
141
  GetSyncStatusResponse,
@@ -153,55 +158,29 @@ from chia.wallet.wallet_request_types import (
153
158
  SelectCoins,
154
159
  SendNotification,
155
160
  SendTransaction,
161
+ SendTransactionMulti,
156
162
  SetWalletResyncOnStartup,
163
+ SignMessageByAddress,
157
164
  SpendClawbackCoins,
158
165
  SplitCoins,
166
+ TakeOffer,
167
+ VCSpend,
159
168
  VerifySignature,
160
169
  VerifySignatureResponse,
170
+ WalletCreationMode,
161
171
  )
162
172
  from chia.wallet.wallet_rpc_api import WalletRpcApi
163
173
  from chia.wallet.wallet_rpc_client import WalletRpcClient
164
- from chia.wallet.wallet_service import WalletService
165
174
  from chia.wallet.wallet_spend_bundle import WalletSpendBundle
166
175
 
167
176
  log = logging.getLogger(__name__)
168
177
 
169
178
 
170
- @dataclasses.dataclass
171
- class WalletBundle:
172
- service: WalletService
173
- node: WalletNode
174
- rpc_client: WalletRpcClient
175
- wallet: Wallet
176
-
177
-
178
- @dataclasses.dataclass
179
- class FullNodeBundle:
180
- server: ChiaServer
181
- api: FullNodeSimulator
182
- rpc_client: FullNodeRpcClient
183
-
184
-
185
- @dataclasses.dataclass
186
- class WalletRpcTestEnvironment:
187
- wallet_1: WalletBundle
188
- wallet_2: WalletBundle
189
- full_node: FullNodeBundle
190
-
191
-
192
- async def check_client_synced(wallet_client: WalletRpcClient) -> bool:
193
- return (await wallet_client.get_sync_status()).synced
194
-
195
-
196
179
  async def farm_transaction_block(full_node_api: FullNodeSimulator, wallet_node: WalletNode) -> None:
197
180
  await full_node_api.farm_blocks_to_puzzlehash(count=1)
198
181
  await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
199
182
 
200
183
 
201
- def check_mempool_spend_count(full_node_api: FullNodeSimulator, num_of_spends: int) -> bool:
202
- return full_node_api.full_node.mempool_manager.mempool.size() == num_of_spends
203
-
204
-
205
184
  async def farm_transaction(
206
185
  full_node_api: FullNodeSimulator, wallet_node: WalletNode, spend_bundle: WalletSpendBundle
207
186
  ) -> None:
@@ -211,124 +190,36 @@ async def farm_transaction(
211
190
  assert full_node_api.full_node.mempool_manager.get_spendbundle(spend_bundle_name) is None
212
191
 
213
192
 
214
- async def generate_funds(full_node_api: FullNodeSimulator, wallet_bundle: WalletBundle, num_blocks: int = 1) -> int:
215
- wallet_id = uint32(1)
216
- initial_balances = (await wallet_bundle.rpc_client.get_wallet_balance(GetWalletBalance(wallet_id))).wallet_balance
217
- ph: bytes32 = decode_puzzle_hash(
218
- (await wallet_bundle.rpc_client.get_next_address(GetNextAddress(wallet_id, True))).address
219
- )
220
- generated_funds = 0
221
- for _ in range(num_blocks):
222
- await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph))
223
- peak_height = full_node_api.full_node.blockchain.get_peak_height()
224
- assert peak_height is not None
225
- generated_funds += calculate_pool_reward(peak_height) + calculate_base_farmer_reward(peak_height)
226
-
227
- # Farm a dummy block to confirm the created funds
228
- await farm_transaction_block(full_node_api, wallet_bundle.node)
229
-
230
- expected_confirmed = initial_balances.confirmed_wallet_balance + generated_funds
231
- expected_unconfirmed = initial_balances.unconfirmed_wallet_balance + generated_funds
232
- await time_out_assert(20, get_confirmed_balance, expected_confirmed, wallet_bundle.rpc_client, wallet_id)
233
- await time_out_assert(20, get_unconfirmed_balance, expected_unconfirmed, wallet_bundle.rpc_client, wallet_id)
234
- await time_out_assert(20, check_client_synced, True, wallet_bundle.rpc_client)
235
-
236
- return generated_funds
237
-
238
-
239
- @pytest.fixture(scope="function", params=[True, False])
240
- async def wallet_rpc_environment(
241
- two_wallet_nodes_services: SimulatorsAndWalletsServices, request: pytest.FixtureRequest, self_hostname: str
242
- ) -> AsyncIterator[WalletRpcTestEnvironment]:
243
- full_node, wallets, bt = two_wallet_nodes_services
244
- full_node_service = full_node[0]
245
- full_node_api = full_node_service._api
246
- full_node_server = full_node_api.full_node.server
247
- wallet_service = wallets[0]
248
- wallet_service_2 = wallets[1]
249
- wallet_node = wallet_service._node
250
- wallet_node_2 = wallet_service_2._node
251
- wallet = wallet_node.wallet_state_manager.main_wallet
252
- wallet_2 = wallet_node_2.wallet_state_manager.main_wallet
253
-
254
- config = bt.config
255
- hostname = config["self_hostname"]
256
-
257
- if request.param:
258
- wallet_node.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
259
- wallet_node_2.config["trusted_peers"] = {full_node_server.node_id.hex(): full_node_server.node_id.hex()}
260
- else:
261
- wallet_node.config["trusted_peers"] = {}
262
- wallet_node_2.config["trusted_peers"] = {}
263
-
264
- await wallet_node.server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
265
- await wallet_node_2.server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None)
266
-
267
- assert wallet_service.rpc_server is not None
268
- async with WalletRpcClient.create_as_context(
269
- hostname, wallet_service.rpc_server.listen_port, wallet_service.root_path, wallet_service.config
270
- ) as client:
271
- assert wallet_service_2.rpc_server is not None
272
- async with WalletRpcClient.create_as_context(
273
- hostname, wallet_service_2.rpc_server.listen_port, wallet_service_2.root_path, wallet_service_2.config
274
- ) as client_2:
275
- assert full_node_service.rpc_server is not None
276
- async with FullNodeRpcClient.create_as_context(
277
- hostname,
278
- full_node_service.rpc_server.listen_port,
279
- full_node_service.root_path,
280
- full_node_service.config,
281
- ) as client_node:
282
- wallet_bundle_1 = WalletBundle(wallet_service, wallet_node, client, wallet)
283
- wallet_bundle_2 = WalletBundle(wallet_service_2, wallet_node_2, client_2, wallet_2)
284
- node_bundle = FullNodeBundle(full_node_server, full_node_api, client_node)
285
-
286
- yield WalletRpcTestEnvironment(wallet_bundle_1, wallet_bundle_2, node_bundle)
287
-
288
-
289
- async def create_tx_outputs(wallet: Wallet, output_args: list[tuple[int, Optional[list[str]]]]) -> list[dict[str, Any]]:
290
- outputs = []
291
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
292
- for args in output_args:
293
- output = {
294
- "amount": uint64(args[0]),
295
- "puzzle_hash": await action_scope.get_puzzle_hash(
296
- wallet.wallet_state_manager, override_reuse_puzhash_with=False
297
- ),
298
- }
299
- if args[1] is not None:
300
- assert len(args[1]) > 0
301
- output["memos"] = args[1]
302
- outputs.append(output)
303
- return outputs
304
-
305
-
306
- async def assert_wallet_types(client: WalletRpcClient, expected: dict[WalletType, int]) -> None:
307
- for wallet_type in WalletType:
308
- wallets = (await client.get_wallets(GetWallets(uint16(wallet_type.value)))).wallets
309
- wallet_count = len(wallets)
310
- if wallet_type in expected:
311
- assert wallet_count == expected.get(wallet_type, 0)
312
- for wallet in wallets:
313
- assert wallet.type == wallet_type.value
193
+ async def create_tx_outputs(
194
+ wallet: Wallet, tx_config: TXConfig, output_args: list[tuple[int, list[str] | None]]
195
+ ) -> list[Addition]:
196
+ async with wallet.wallet_state_manager.new_action_scope(tx_config, push=True) as action_scope:
197
+ return [
198
+ Addition(
199
+ amount=uint64(args[0]),
200
+ puzzle_hash=await action_scope.get_puzzle_hash(wallet.wallet_state_manager),
201
+ memos=None if args[1] is None or len(args[1]) == 0 else args[1],
202
+ )
203
+ for args in output_args
204
+ ]
314
205
 
315
206
 
316
207
  def assert_tx_amounts(
317
208
  tx: TransactionRecord,
318
- outputs: list[dict[str, Any]],
209
+ outputs: list[Addition],
319
210
  *,
320
211
  amount_fee: uint64,
321
212
  change_expected: bool,
322
213
  is_cat: bool = False,
323
214
  ) -> None:
324
215
  assert tx.fee_amount == amount_fee
325
- assert tx.amount == sum(output["amount"] for output in outputs)
216
+ assert tx.amount == sum(output.amount for output in outputs)
326
217
  expected_additions = len(outputs) + 1 if change_expected else len(outputs)
327
218
  assert len(tx.additions) == expected_additions
328
219
  addition_amounts = [addition.amount for addition in tx.additions]
329
220
  removal_amounts = [removal.amount for removal in tx.removals]
330
221
  for output in outputs:
331
- assert output["amount"] in addition_amounts
222
+ assert output.amount in addition_amounts
332
223
  if is_cat:
333
224
  assert (sum(removal_amounts) - sum(addition_amounts)) == 0
334
225
  else:
@@ -356,7 +247,7 @@ async def assert_get_balance(rpc_client: WalletRpcClient, wallet_node: WalletNod
356
247
  expected_balance_dict["fingerprint"] = wallet_node.logged_in_fingerprint
357
248
  if wallet.type() in {WalletType.CAT, WalletType.CRCAT}:
358
249
  assert isinstance(wallet, CATWallet)
359
- expected_balance_dict["asset_id"] = "0x" + wallet.get_asset_id()
250
+ expected_balance_dict["asset_id"] = "0x" + wallet.get_asset_id().hex()
360
251
  else:
361
252
  expected_balance_dict["asset_id"] = None
362
253
  assert (
@@ -381,24 +272,34 @@ async def get_unconfirmed_balance(client: WalletRpcClient, wallet_id: int) -> ui
381
272
  ).wallet_balance.unconfirmed_wallet_balance
382
273
 
383
274
 
275
+ @pytest.mark.parametrize(
276
+ "wallet_environments",
277
+ [
278
+ {
279
+ "num_environments": 2,
280
+ "blocks_needed": [1, 1],
281
+ }
282
+ ],
283
+ indirect=True,
284
+ )
285
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
384
286
  @pytest.mark.anyio
385
- async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
386
- env: WalletRpcTestEnvironment = wallet_rpc_environment
387
-
388
- wallet_2: Wallet = env.wallet_2.wallet
389
- wallet_node: WalletNode = env.wallet_1.node
390
- full_node_api: FullNodeSimulator = env.full_node.api
391
- client: WalletRpcClient = env.wallet_1.rpc_client
392
-
393
- generated_funds = await generate_funds(full_node_api, env.wallet_1)
287
+ async def test_send_transaction(wallet_environments: WalletTestFramework) -> None:
288
+ env = wallet_environments.environments[0]
289
+ env_2 = wallet_environments.environments[1]
290
+ wallet_2: Wallet = env_2.xch_wallet
291
+ wallet_node: WalletNode = env.node
292
+ full_node_api: FullNodeSimulator = wallet_environments.full_node
293
+ client: WalletRpcClient = env.rpc_client
394
294
 
395
- async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
295
+ INITIAL_FUNDS = await env.xch_wallet.get_confirmed_balance()
296
+ async with wallet_2.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
396
297
  addr = encode_puzzle_hash(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager), "txch")
397
298
  tx_amount = uint64(15600000)
398
299
  with pytest.raises(ValueError):
399
300
  await client.send_transaction(
400
301
  SendTransaction(wallet_id=uint32(1), amount=uint64(100000000000000001), address=addr, push=True),
401
- DEFAULT_TX_CONFIG,
302
+ wallet_environments.tx_config,
402
303
  )
403
304
 
404
305
  # Tests sending a basic transaction
@@ -409,7 +310,7 @@ async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment
409
310
  SendTransaction(
410
311
  wallet_id=uint32(1), amount=tx_amount, address=addr, memos=["this is a basic tx"], push=False
411
312
  ),
412
- tx_config=DEFAULT_TX_CONFIG.override(
313
+ tx_config=wallet_environments.tx_config.override(
413
314
  excluded_coin_amounts=[uint64(250000000000)],
414
315
  excluded_coin_ids=[non_existent_coin.name()],
415
316
  reuse_puzhash=True,
@@ -449,7 +350,7 @@ async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment
449
350
  assert spend_bundle is not None
450
351
 
451
352
  await time_out_assert(20, tx_in_mempool, True, client, transaction_id)
452
- await time_out_assert(20, get_unconfirmed_balance, generated_funds - tx_amount, client, 1)
353
+ await time_out_assert(20, get_unconfirmed_balance, INITIAL_FUNDS - tx_amount, client, 1)
453
354
 
454
355
  await farm_transaction(full_node_api, wallet_node, spend_bundle)
455
356
 
@@ -460,38 +361,56 @@ async def test_send_transaction(wallet_rpc_environment: WalletRpcTestEnvironment
460
361
  assert [b"this is a basic tx"] in tx_confirmed.memos.values()
461
362
  assert next(iter(tx_confirmed.memos.keys())) in [a.name() for a in spend_bundle.additions()]
462
363
 
463
- await time_out_assert(20, get_confirmed_balance, generated_funds - tx_amount, client, 1)
364
+ await time_out_assert(20, get_confirmed_balance, INITIAL_FUNDS - tx_amount, client, 1)
464
365
 
465
366
 
367
+ @pytest.mark.parametrize(
368
+ "wallet_environments",
369
+ [
370
+ {
371
+ "num_environments": 1,
372
+ "blocks_needed": [2],
373
+ }
374
+ ],
375
+ indirect=True,
376
+ )
377
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
466
378
  @pytest.mark.anyio
467
- async def test_push_transactions(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
468
- env: WalletRpcTestEnvironment = wallet_rpc_environment
469
-
470
- wallet: Wallet = env.wallet_1.wallet
471
- wallet_node: WalletNode = env.wallet_1.node
472
- full_node_api: FullNodeSimulator = env.full_node.api
473
- client: WalletRpcClient = env.wallet_1.rpc_client
379
+ async def test_push_transactions(wallet_environments: WalletTestFramework) -> None:
380
+ env = wallet_environments.environments[0]
474
381
 
475
- await generate_funds(full_node_api, env.wallet_1, num_blocks=2)
382
+ wallet: Wallet = env.xch_wallet
383
+ wallet_node: WalletNode = env.node
384
+ full_node_api: FullNodeSimulator = wallet_environments.full_node
385
+ client: WalletRpcClient = env.rpc_client
476
386
 
477
- outputs = await create_tx_outputs(wallet, [(1234321, None)])
387
+ outputs = await create_tx_outputs(wallet, wallet_environments.tx_config, [(1234321, None)])
478
388
 
479
389
  tx = (
480
390
  await client.create_signed_transactions(
481
- outputs,
482
- tx_config=DEFAULT_TX_CONFIG,
483
- fee=uint64(100),
391
+ CreateSignedTransaction(additions=outputs, fee=uint64(100)),
392
+ tx_config=wallet_environments.tx_config,
484
393
  )
485
394
  ).signed_tx
486
395
 
396
+ with pytest.raises(ValueError, match="Cannot add conditions to a transaction if no new fee spend is being added"):
397
+ await client.push_transactions(
398
+ PushTransactions(transactions=[tx]),
399
+ tx_config=wallet_environments.tx_config,
400
+ extra_conditions=(Remark(rest=Program.to("foo")),),
401
+ )
402
+
487
403
  resp_client = await client.push_transactions(
488
404
  PushTransactions(transactions=[tx], fee=uint64(10)),
489
- DEFAULT_TX_CONFIG,
405
+ wallet_environments.tx_config,
490
406
  )
407
+ await full_node_api.wait_for_wallet_synced(wallet_node)
491
408
  resp = await client.fetch("push_transactions", {"transactions": [tx.to_json_dict()], "fee": 10})
492
409
  assert resp["success"]
410
+ await full_node_api.wait_for_wallet_synced(wallet_node)
493
411
  resp = await client.fetch("push_transactions", {"transactions": [bytes(tx).hex()], "fee": 10})
494
412
  assert resp["success"]
413
+ await full_node_api.wait_for_wallet_synced(wallet_node)
495
414
 
496
415
  spend_bundle = WalletSpendBundle.aggregate(
497
416
  [tx.spend_bundle for tx in resp_client.transactions if tx.spend_bundle is not None]
@@ -508,15 +427,25 @@ async def test_push_transactions(wallet_rpc_environment: WalletRpcTestEnvironmen
508
427
  assert resp["success"]
509
428
 
510
429
 
430
+ @pytest.mark.parametrize(
431
+ "wallet_environments",
432
+ [
433
+ {
434
+ "num_environments": 1,
435
+ "blocks_needed": [1],
436
+ }
437
+ ],
438
+ indirect=True,
439
+ )
440
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
511
441
  @pytest.mark.anyio
512
- async def test_get_balance(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
513
- env = wallet_rpc_environment
514
- wallet: Wallet = env.wallet_1.wallet
515
- wallet_node: WalletNode = env.wallet_1.node
516
- full_node_api: FullNodeSimulator = env.full_node.api
517
- wallet_rpc_client = env.wallet_1.rpc_client
518
- await full_node_api.farm_blocks_to_wallet(2, wallet)
519
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
442
+ async def test_get_balance(wallet_environments: WalletTestFramework) -> None:
443
+ env = wallet_environments.environments[0]
444
+ wallet: Wallet = env.xch_wallet
445
+ wallet_node: WalletNode = env.node
446
+ full_node_api: FullNodeSimulator = wallet_environments.full_node
447
+ wallet_rpc_client = env.rpc_client
448
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
520
449
  cat_wallet = await CATWallet.create_new_cat_wallet(
521
450
  wallet_node.wallet_state_manager,
522
451
  wallet,
@@ -530,44 +459,50 @@ async def test_get_balance(wallet_rpc_environment: WalletRpcTestEnvironment) ->
530
459
  await assert_get_balance(wallet_rpc_client, wallet_node, cat_wallet)
531
460
 
532
461
 
462
+ @pytest.mark.parametrize(
463
+ "wallet_environments",
464
+ [{"num_environments": 1, "blocks_needed": [2], "reuse_puzhash": True, "trusted": True}],
465
+ indirect=True,
466
+ )
467
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
533
468
  @pytest.mark.anyio
534
- async def test_get_farmed_amount(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
535
- env = wallet_rpc_environment
536
- wallet: Wallet = env.wallet_1.wallet
537
- full_node_api: FullNodeSimulator = env.full_node.api
538
- wallet_rpc_client = env.wallet_1.rpc_client
539
- await full_node_api.farm_blocks_to_wallet(2, wallet)
540
-
541
- get_farmed_amount_result = await wallet_rpc_client.get_farmed_amount()
469
+ async def test_get_farmed_amount(wallet_environments: WalletTestFramework) -> None:
470
+ env = wallet_environments.environments[0]
471
+ wallet_rpc_client = env.rpc_client
472
+
473
+ get_farmed_amount_result = await wallet_rpc_client.get_farmed_amount(GetFarmedAmount())
542
474
  get_timestamp_for_height_result = await wallet_rpc_client.get_timestamp_for_height(
543
475
  GetTimestampForHeight(uint32(3))
544
476
  ) # genesis + 2
545
477
 
546
- expected_result = {
547
- "blocks_won": 2,
548
- "farmed_amount": 4_000_000_000_000,
549
- "farmer_reward_amount": 500_000_000_000,
550
- "fee_amount": 0,
551
- "last_height_farmed": 3,
552
- "last_time_farmed": get_timestamp_for_height_result.timestamp,
553
- "pool_reward_amount": 3_500_000_000_000,
554
- "success": True,
555
- }
478
+ expected_result = GetFarmedAmountResponse(
479
+ blocks_won=uint32(2),
480
+ farmed_amount=uint64(4_000_000_000_000),
481
+ farmer_reward_amount=uint64(500_000_000_000),
482
+ fee_amount=uint64(0),
483
+ last_height_farmed=uint32(3),
484
+ last_time_farmed=uint64(get_timestamp_for_height_result.timestamp),
485
+ pool_reward_amount=uint64(3_500_000_000_000),
486
+ )
556
487
  assert get_farmed_amount_result == expected_result
557
488
 
558
489
 
490
+ @pytest.mark.parametrize(
491
+ "wallet_environments",
492
+ [{"num_environments": 1, "blocks_needed": [2], "reuse_puzhash": True, "trusted": True}],
493
+ indirect=True,
494
+ )
495
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
559
496
  @pytest.mark.anyio
560
- async def test_get_farmed_amount_with_fee(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
561
- env = wallet_rpc_environment
562
- wallet: Wallet = env.wallet_1.wallet
563
- full_node_api: FullNodeSimulator = env.full_node.api
564
- wallet_rpc_client = env.wallet_1.rpc_client
565
- wallet_node: WalletNode = env.wallet_1.node
566
-
567
- await generate_funds(full_node_api, env.wallet_1)
497
+ async def test_get_farmed_amount_with_fee(wallet_environments: WalletTestFramework) -> None:
498
+ env = wallet_environments.environments[0]
499
+ wallet: Wallet = env.xch_wallet
500
+ full_node_api: FullNodeSimulator = wallet_environments.full_node
501
+ wallet_rpc_client = env.rpc_client
502
+ wallet_node: WalletNode = env.node
568
503
 
569
504
  fee_amount = 100
570
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
505
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
571
506
  await wallet.generate_signed_transaction(
572
507
  amounts=[uint64(5)],
573
508
  puzzle_hashes=[bytes32.zeros],
@@ -580,18 +515,20 @@ async def test_get_farmed_amount_with_fee(wallet_rpc_environment: WalletRpcTestE
580
515
  await full_node_api.farm_blocks_to_puzzlehash(count=2, farm_to=our_ph, guarantee_transaction_blocks=True)
581
516
  await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
582
517
 
583
- result = await wallet_rpc_client.get_farmed_amount()
584
- assert result["fee_amount"] == fee_amount
518
+ result = await wallet_rpc_client.get_farmed_amount(GetFarmedAmount())
519
+ assert result.fee_amount == fee_amount
585
520
 
586
521
 
522
+ @pytest.mark.parametrize(
523
+ "wallet_environments",
524
+ [{"num_environments": 1, "blocks_needed": [1], "reuse_puzhash": True, "trusted": True}],
525
+ indirect=True,
526
+ )
527
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
587
528
  @pytest.mark.anyio
588
- async def test_get_timestamp_for_height(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
589
- env: WalletRpcTestEnvironment = wallet_rpc_environment
590
-
591
- full_node_api: FullNodeSimulator = env.full_node.api
592
- client: WalletRpcClient = env.wallet_1.rpc_client
593
-
594
- await generate_funds(full_node_api, env.wallet_1)
529
+ async def test_get_timestamp_for_height(wallet_environments: WalletTestFramework) -> None:
530
+ env = wallet_environments.environments[0]
531
+ client: WalletRpcClient = env.rpc_client
595
532
 
596
533
  # This tests that the client returns successfully, rather than raising or returning something unexpected
597
534
  await client.get_timestamp_for_height(GetTimestampForHeight(uint32(1)))
@@ -613,44 +550,74 @@ async def test_get_timestamp_for_height(wallet_rpc_environment: WalletRpcTestEnv
613
550
  ([(120000000000, None), (120000000000, None)], 10000000000, True, False),
614
551
  ],
615
552
  )
553
+ @pytest.mark.parametrize(
554
+ "wallet_environments",
555
+ [{"num_environments": 2, "blocks_needed": [2, 1], "config_overrides": {"automatically_add_unknown_cats": True}}],
556
+ indirect=True,
557
+ )
558
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
616
559
  @pytest.mark.anyio
617
560
  async def test_create_signed_transaction(
618
- wallet_rpc_environment: WalletRpcTestEnvironment,
619
- output_args: list[tuple[int, Optional[list[str]]]],
561
+ wallet_environments: WalletTestFramework,
562
+ output_args: list[tuple[int, list[str] | None]],
620
563
  fee: int,
621
564
  select_coin: bool,
622
565
  is_cat: bool,
623
566
  ) -> None:
624
- env: WalletRpcTestEnvironment = wallet_rpc_environment
567
+ if (
568
+ len(set(amount for amount, _ in output_args)) != len(output_args)
569
+ and wallet_environments.tx_config.reuse_puzhash
570
+ ):
571
+ pytest.skip("Skipping reuse_puzhash + identical amounts for simplicity sake")
572
+ env = wallet_environments.environments[0]
573
+ env_2 = wallet_environments.environments[1]
574
+
575
+ wallet_2: Wallet = env_2.xch_wallet
576
+ wallet_1_rpc: WalletRpcClient = env.rpc_client
577
+ full_node_rpc: FullNodeRpcClient = wallet_environments.full_node_rpc_client
625
578
 
626
- wallet_2: Wallet = env.wallet_2.wallet
627
- wallet_1_node: WalletNode = env.wallet_1.node
628
- wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
629
- full_node_api: FullNodeSimulator = env.full_node.api
630
- full_node_rpc: FullNodeRpcClient = env.full_node.rpc_client
579
+ env.wallet_aliases = {"xch": 1, "cat": 2}
580
+ env_2.wallet_aliases = {"xch": 1, "cat": 2}
631
581
 
632
- generated_funds = await generate_funds(full_node_api, env.wallet_1)
582
+ outputs = await create_tx_outputs(wallet_2, wallet_environments.tx_config, output_args)
583
+ amount_outputs = sum(output.amount for output in outputs)
584
+ amount_fee = uint64(fee)
633
585
 
634
586
  wallet_id = 1
635
587
  if is_cat:
636
- generated_funds = 10**9
637
-
638
- res = await wallet_1_rpc.create_new_cat_and_wallet(uint64(generated_funds), test=True)
639
- assert res["success"]
640
- wallet_id = res["wallet_id"]
641
-
642
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
643
- for _ in range(5):
644
- if check_mempool_spend_count(full_node_api, 0):
645
- break
646
- await farm_transaction_block(full_node_api, wallet_1_node)
588
+ create_cat_res = await wallet_1_rpc.create_new_wallet(
589
+ CreateNewWallet(
590
+ wallet_type=CreateNewWalletType.CAT_WALLET,
591
+ mode=WalletCreationMode.NEW,
592
+ amount=uint64(amount_outputs + 1),
593
+ test=True,
594
+ push=True,
595
+ ),
596
+ tx_config=wallet_environments.tx_config,
597
+ )
598
+ wallet_id = create_cat_res.wallet_id
647
599
 
648
- outputs = await create_tx_outputs(wallet_2, output_args)
649
- amount_outputs = sum(output["amount"] for output in outputs)
650
- amount_fee = uint64(fee)
600
+ await wallet_environments.process_pending_states(
601
+ [
602
+ WalletStateTransition(
603
+ pre_block_balance_updates={
604
+ "xch": {"set_remainder": True},
605
+ "cat": {"init": True, "set_remainder": True},
606
+ },
607
+ post_block_balance_updates={
608
+ "xch": {"set_remainder": True},
609
+ "cat": {"set_remainder": True},
610
+ },
611
+ ),
612
+ WalletStateTransition(
613
+ pre_block_balance_updates={},
614
+ post_block_balance_updates={},
615
+ ),
616
+ ]
617
+ )
651
618
 
652
619
  if is_cat:
653
- amount_total = amount_outputs
620
+ amount_total: int = amount_outputs
654
621
  else:
655
622
  amount_total = amount_outputs + amount_fee
656
623
 
@@ -658,7 +625,9 @@ async def test_create_signed_transaction(
658
625
  if select_coin:
659
626
  select_coins_response = await wallet_1_rpc.select_coins(
660
627
  SelectCoins.from_coin_selection_config(
661
- amount=amount_total, wallet_id=uint32(wallet_id), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
628
+ amount=uint64(amount_total),
629
+ wallet_id=uint32(wallet_id),
630
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config,
662
631
  )
663
632
  )
664
633
  assert len(select_coins_response.coins) == 1
@@ -666,15 +635,17 @@ async def test_create_signed_transaction(
666
635
 
667
636
  txs = (
668
637
  await wallet_1_rpc.create_signed_transactions(
669
- outputs,
670
- coins=[selected_coin] if selected_coin is not None else [],
671
- fee=amount_fee,
672
- wallet_id=wallet_id,
638
+ CreateSignedTransaction(
639
+ additions=outputs,
640
+ coins=[selected_coin] if selected_coin is not None else None,
641
+ fee=amount_fee,
642
+ wallet_id=uint32(wallet_id),
643
+ push=True,
644
+ ),
673
645
  # shouldn't actually block it
674
- tx_config=DEFAULT_TX_CONFIG.override(
646
+ tx_config=wallet_environments.tx_config.override(
675
647
  excluded_coin_amounts=[uint64(selected_coin.amount)] if selected_coin is not None else [],
676
648
  ),
677
- push=True,
678
649
  )
679
650
  ).transactions
680
651
  change_expected = not selected_coin or selected_coin.amount - amount_total > 0
@@ -683,8 +654,72 @@ async def test_create_signed_transaction(
683
654
  # Farm the transaction and make sure the wallet balance reflects it correct
684
655
  spend_bundle = txs[0].spend_bundle
685
656
  assert spend_bundle is not None
686
- await farm_transaction(full_node_api, wallet_1_node, spend_bundle)
687
- await time_out_assert(20, get_confirmed_balance, generated_funds - amount_total, wallet_1_rpc, wallet_id)
657
+ xch_delta = amount_total if not is_cat else amount_fee
658
+ cat_delta = amount_total if is_cat else 0
659
+ await wallet_environments.process_pending_states(
660
+ [
661
+ WalletStateTransition(
662
+ pre_block_balance_updates={ # type: ignore[arg-type]
663
+ "xch": {
664
+ "unconfirmed_wallet_balance": -xch_delta,
665
+ "<=#spendable_balance": -xch_delta,
666
+ "<=#max_send_amount": -xch_delta,
667
+ ">=#pending_change": 0,
668
+ "pending_coin_removal_count": 1,
669
+ }
670
+ }
671
+ | (
672
+ {
673
+ "cat": {
674
+ "unconfirmed_wallet_balance": -cat_delta,
675
+ "<=#spendable_balance": -cat_delta,
676
+ "<=#max_send_amount": -cat_delta,
677
+ ">=#pending_change": 1 if is_cat else 0,
678
+ "pending_coin_removal_count": 1 if is_cat else 0,
679
+ }
680
+ }
681
+ if is_cat
682
+ else {}
683
+ ),
684
+ post_block_balance_updates={ # type: ignore[arg-type]
685
+ "xch": {
686
+ "confirmed_wallet_balance": -xch_delta,
687
+ ">=#spendable_balance": 0,
688
+ ">=#max_send_amount": 0,
689
+ "<=#pending_change": 0,
690
+ "pending_coin_removal_count": -1,
691
+ "<=#unspent_coin_count": 0,
692
+ }
693
+ }
694
+ | (
695
+ {
696
+ "cat": {
697
+ "confirmed_wallet_balance": -cat_delta,
698
+ ">=#spendable_balance": 1 if is_cat else 0,
699
+ ">=#max_send_amount": 1 if is_cat else 0,
700
+ "<=#pending_change": -1 if is_cat else 0,
701
+ "pending_coin_removal_count": -1 if is_cat else 0,
702
+ }
703
+ }
704
+ if is_cat
705
+ else {}
706
+ ),
707
+ ),
708
+ WalletStateTransition(
709
+ pre_block_balance_updates={},
710
+ post_block_balance_updates={
711
+ "cat" if is_cat else "xch": {
712
+ "init": is_cat,
713
+ "confirmed_wallet_balance": amount_outputs,
714
+ "unconfirmed_wallet_balance": amount_outputs,
715
+ "spendable_balance": amount_outputs,
716
+ "max_send_amount": amount_outputs,
717
+ "unspent_coin_count": len(outputs),
718
+ }
719
+ },
720
+ ),
721
+ ]
722
+ )
688
723
 
689
724
  # Assert every coin comes from the same parent
690
725
  additions: list[Coin] = spend_bundle.additions()
@@ -692,9 +727,9 @@ async def test_create_signed_transaction(
692
727
 
693
728
  # Assert you can get the spend for each addition
694
729
  for addition in additions:
695
- cr: Optional[CoinRecord] = await full_node_rpc.get_coin_record_by_name(addition.name())
730
+ cr: CoinRecord | None = await full_node_rpc.get_coin_record_by_name(addition.name())
696
731
  assert cr is not None
697
- spend: Optional[CoinSpend] = await full_node_rpc.get_puzzle_and_solution(
732
+ spend: CoinSpend | None = await full_node_rpc.get_puzzle_and_solution(
698
733
  addition.parent_coin_info, cr.confirmed_block_index
699
734
  )
700
735
  assert spend is not None
@@ -703,35 +738,37 @@ async def test_create_signed_transaction(
703
738
  addition_dict: dict[bytes32, Coin] = {addition.name(): addition for addition in additions}
704
739
  memo_dictionary: dict[bytes32, list[bytes]] = compute_memos(spend_bundle)
705
740
  for output in outputs:
706
- if "memos" in output:
741
+ if output.memos is not None:
707
742
  found: bool = False
708
743
  for addition_id, addition in addition_dict.items():
709
744
  if (
710
745
  is_cat
711
- and addition.amount == output["amount"]
712
- and memo_dictionary[addition_id][0] == output["puzzle_hash"]
713
- and memo_dictionary[addition_id][1:] == [memo.encode() for memo in output["memos"]]
746
+ and addition.amount == output.amount
747
+ and memo_dictionary[addition_id][0] == output.puzzle_hash
748
+ and memo_dictionary[addition_id][1:] == [memo.encode() for memo in output.memos]
714
749
  ) or (
715
- addition.amount == output["amount"]
716
- and addition.puzzle_hash == output["puzzle_hash"]
717
- and memo_dictionary[addition_id] == [memo.encode() for memo in output["memos"]]
750
+ addition.amount == output.amount
751
+ and addition.puzzle_hash == output.puzzle_hash
752
+ and memo_dictionary[addition_id] == [memo.encode() for memo in output.memos]
718
753
  ):
719
754
  found = True
720
755
  assert found
721
756
 
722
757
 
758
+ @pytest.mark.parametrize(
759
+ "wallet_environments",
760
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
761
+ indirect=True,
762
+ )
763
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
723
764
  @pytest.mark.anyio
724
- async def test_create_signed_transaction_with_coin_announcement(
725
- wallet_rpc_environment: WalletRpcTestEnvironment,
726
- ) -> None:
727
- env: WalletRpcTestEnvironment = wallet_rpc_environment
728
-
729
- wallet_2: Wallet = env.wallet_2.wallet
730
- full_node_api: FullNodeSimulator = env.full_node.api
731
- client: WalletRpcClient = env.wallet_1.rpc_client
732
- client_node: FullNodeRpcClient = env.full_node.rpc_client
765
+ async def test_create_signed_transaction_with_coin_announcement(wallet_environments: WalletTestFramework) -> None:
766
+ env = wallet_environments.environments[0]
767
+ env_2 = wallet_environments.environments[1]
733
768
 
734
- await generate_funds(full_node_api, env.wallet_1)
769
+ wallet_2: Wallet = env_2.xch_wallet
770
+ client: WalletRpcClient = env.rpc_client
771
+ client_node: FullNodeRpcClient = wallet_environments.full_node_rpc_client
735
772
 
736
773
  signed_tx_amount = uint64(888000)
737
774
  tx_coin_announcements = [
@@ -744,28 +781,32 @@ async def test_create_signed_transaction_with_coin_announcement(
744
781
  std_hash(b"coin_id_2"),
745
782
  ),
746
783
  ]
747
- outputs = await create_tx_outputs(wallet_2, [(signed_tx_amount, None)])
784
+ outputs = await create_tx_outputs(wallet_2, wallet_environments.tx_config, [(signed_tx_amount, None)])
748
785
  tx_res: TransactionRecord = (
749
786
  await client.create_signed_transactions(
750
- outputs, tx_config=DEFAULT_TX_CONFIG, extra_conditions=(*tx_coin_announcements,)
787
+ CreateSignedTransaction(additions=outputs),
788
+ tx_config=wallet_environments.tx_config,
789
+ extra_conditions=(*tx_coin_announcements,),
751
790
  )
752
791
  ).signed_tx
753
792
  assert_tx_amounts(tx_res, outputs, amount_fee=uint64(0), change_expected=True)
754
793
  await assert_push_tx_error(client_node, tx_res)
755
794
 
756
795
 
796
+ @pytest.mark.parametrize(
797
+ "wallet_environments",
798
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
799
+ indirect=True,
800
+ )
801
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
757
802
  @pytest.mark.anyio
758
- async def test_create_signed_transaction_with_puzzle_announcement(
759
- wallet_rpc_environment: WalletRpcTestEnvironment,
760
- ) -> None:
761
- env: WalletRpcTestEnvironment = wallet_rpc_environment
762
-
763
- wallet_2: Wallet = env.wallet_2.wallet
764
- full_node_api: FullNodeSimulator = env.full_node.api
765
- client: WalletRpcClient = env.wallet_1.rpc_client
766
- client_node: FullNodeRpcClient = env.full_node.rpc_client
803
+ async def test_create_signed_transaction_with_puzzle_announcement(wallet_environments: WalletTestFramework) -> None:
804
+ env = wallet_environments.environments[0]
805
+ env_2 = wallet_environments.environments[1]
767
806
 
768
- await generate_funds(full_node_api, env.wallet_1)
807
+ wallet_2: Wallet = env_2.xch_wallet
808
+ client: WalletRpcClient = env.rpc_client
809
+ client_node: FullNodeRpcClient = wallet_environments.full_node_rpc_client
769
810
 
770
811
  signed_tx_amount = uint64(888000)
771
812
  tx_puzzle_announcements = [
@@ -778,38 +819,46 @@ async def test_create_signed_transaction_with_puzzle_announcement(
778
819
  std_hash(b"puzzle_hash_2"),
779
820
  ),
780
821
  ]
781
- outputs = await create_tx_outputs(wallet_2, [(signed_tx_amount, None)])
822
+ outputs = await create_tx_outputs(wallet_2, wallet_environments.tx_config, [(signed_tx_amount, None)])
782
823
  tx_res = (
783
824
  await client.create_signed_transactions(
784
- outputs, tx_config=DEFAULT_TX_CONFIG, extra_conditions=(*tx_puzzle_announcements,)
825
+ CreateSignedTransaction(additions=outputs),
826
+ tx_config=wallet_environments.tx_config,
827
+ extra_conditions=(*tx_puzzle_announcements,),
785
828
  )
786
829
  ).signed_tx
787
830
  assert_tx_amounts(tx_res, outputs, amount_fee=uint64(0), change_expected=True)
788
831
  await assert_push_tx_error(client_node, tx_res)
789
832
 
790
833
 
834
+ @pytest.mark.parametrize(
835
+ "wallet_environments",
836
+ [{"num_environments": 1, "blocks_needed": [1]}],
837
+ indirect=True,
838
+ )
839
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
791
840
  @pytest.mark.anyio
792
- async def test_create_signed_transaction_with_excluded_coins(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
793
- env: WalletRpcTestEnvironment = wallet_rpc_environment
794
- wallet_1: Wallet = env.wallet_1.wallet
795
- wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
796
- full_node_api: FullNodeSimulator = env.full_node.api
797
- full_node_rpc: FullNodeRpcClient = env.full_node.rpc_client
798
- await generate_funds(full_node_api, env.wallet_1)
841
+ async def test_create_signed_transaction_with_excluded_coins(wallet_environments: WalletTestFramework) -> None:
842
+ env = wallet_environments.environments[0]
843
+ wallet_1: Wallet = env.xch_wallet
844
+ wallet_1_rpc: WalletRpcClient = env.rpc_client
845
+ full_node_rpc: FullNodeRpcClient = wallet_environments.full_node_rpc_client
799
846
 
800
847
  async def it_does_not_include_the_excluded_coins() -> None:
801
848
  select_coins_response = await wallet_1_rpc.select_coins(
802
849
  SelectCoins.from_coin_selection_config(
803
- amount=uint64(250000000000), wallet_id=uint32(1), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
850
+ amount=uint64(250000000000),
851
+ wallet_id=uint32(1),
852
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config,
804
853
  )
805
854
  )
806
855
  assert len(select_coins_response.coins) == 1
807
- outputs = await create_tx_outputs(wallet_1, [(uint64(250000000000), None)])
856
+ outputs = await create_tx_outputs(wallet_1, wallet_environments.tx_config, [(uint64(250000000000), None)])
808
857
 
809
858
  tx = (
810
859
  await wallet_1_rpc.create_signed_transactions(
811
- outputs,
812
- DEFAULT_TX_CONFIG.override(
860
+ CreateSignedTransaction(additions=outputs),
861
+ wallet_environments.tx_config.override(
813
862
  excluded_coin_ids=[c.name() for c in select_coins_response.coins],
814
863
  ),
815
864
  )
@@ -823,16 +872,18 @@ async def test_create_signed_transaction_with_excluded_coins(wallet_rpc_environm
823
872
  async def it_throws_an_error_when_all_spendable_coins_are_excluded() -> None:
824
873
  select_coins_response = await wallet_1_rpc.select_coins(
825
874
  SelectCoins.from_coin_selection_config(
826
- amount=uint64(1750000000000), wallet_id=uint32(1), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
875
+ amount=uint64(1750000000000),
876
+ wallet_id=uint32(1),
877
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config,
827
878
  )
828
879
  )
829
880
  assert len(select_coins_response.coins) == 1
830
- outputs = await create_tx_outputs(wallet_1, [(uint64(1750000000000), None)])
881
+ outputs = await create_tx_outputs(wallet_1, wallet_environments.tx_config, [(uint64(1750000000000), None)])
831
882
 
832
883
  with pytest.raises(ValueError):
833
884
  await wallet_1_rpc.create_signed_transactions(
834
- outputs,
835
- DEFAULT_TX_CONFIG.override(
885
+ CreateSignedTransaction(additions=outputs),
886
+ wallet_environments.tx_config.override(
836
887
  excluded_coin_ids=[c.name() for c in select_coins_response.coins],
837
888
  ),
838
889
  )
@@ -841,159 +892,47 @@ async def test_create_signed_transaction_with_excluded_coins(wallet_rpc_environm
841
892
  await it_throws_an_error_when_all_spendable_coins_are_excluded()
842
893
 
843
894
 
895
+ @pytest.mark.parametrize(
896
+ "wallet_environments",
897
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
898
+ indirect=True,
899
+ )
900
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
844
901
  @pytest.mark.anyio
845
- async def test_spend_clawback_coins(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
846
- env: WalletRpcTestEnvironment = wallet_rpc_environment
847
-
848
- wallet_1_node: WalletNode = env.wallet_1.node
849
- wallet_2_node: WalletNode = env.wallet_2.node
850
- wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
851
- wallet_2_rpc: WalletRpcClient = env.wallet_2.rpc_client
852
- wallet_1 = wallet_1_node.wallet_state_manager.main_wallet
853
- wallet_2 = wallet_2_node.wallet_state_manager.main_wallet
854
- full_node_api: FullNodeSimulator = env.full_node.api
855
-
856
- generated_funds = await generate_funds(full_node_api, env.wallet_1, 1)
857
- await generate_funds(full_node_api, env.wallet_2, 1)
858
- async with wallet_1.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
859
- wallet_1_puzhash = await action_scope.get_puzzle_hash(wallet_1.wallet_state_manager)
860
- await full_node_api.wait_for_wallet_synced(wallet_node=wallet_1_node, timeout=20)
861
- async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
862
- wallet_2_puzhash = await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)
863
- tx = (
864
- await wallet_1_rpc.send_transaction(
865
- SendTransaction(
866
- wallet_id=uint32(1),
867
- amount=uint64(500),
868
- address=encode_puzzle_hash(wallet_2_puzhash, "txch"),
869
- puzzle_decorator=[ClawbackPuzzleDecoratorOverride(decorator="CLAWBACK", clawback_timelock=uint64(5))],
870
- push=True,
871
- ),
872
- tx_config=DEFAULT_TX_CONFIG,
873
- )
874
- ).transaction
875
- clawback_coin_id_1 = tx.additions[0].name()
876
- assert tx.spend_bundle is not None
877
- await farm_transaction(full_node_api, wallet_1_node, tx.spend_bundle)
878
- await full_node_api.wait_for_wallet_synced(wallet_node=wallet_2_node, timeout=20)
879
- tx = (
880
- await wallet_2_rpc.send_transaction(
881
- SendTransaction(
882
- wallet_id=uint32(1),
883
- amount=uint64(500),
884
- address=encode_puzzle_hash(wallet_1_puzhash, "txch"),
885
- puzzle_decorator=[ClawbackPuzzleDecoratorOverride(decorator="CLAWBACK", clawback_timelock=uint64(5))],
886
- push=True,
887
- ),
888
- tx_config=DEFAULT_TX_CONFIG,
889
- )
890
- ).transaction
891
- assert tx.spend_bundle is not None
892
- clawback_coin_id_2 = tx.additions[0].name()
893
- await farm_transaction(full_node_api, wallet_2_node, tx.spend_bundle)
894
- await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_1_rpc, 1)
895
- await time_out_assert(20, get_confirmed_balance, generated_funds - 500, wallet_2_rpc, 1)
896
- await asyncio.sleep(10)
897
- # Test coin ID is not a Clawback coin
898
- invalid_coin_id = tx.removals[0].name()
899
- resp = await wallet_2_rpc.spend_clawback_coins(
900
- SpendClawbackCoins(coin_ids=[invalid_coin_id], fee=uint64(500), push=True), tx_config=DEFAULT_TX_CONFIG
901
- )
902
- assert resp.transaction_ids == []
903
- # Test unsupported wallet
904
- coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_1)
905
- assert coin_record is not None
906
- await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
907
- dataclasses.replace(coin_record, wallet_type=WalletType.CAT)
908
- )
909
- resp = await wallet_1_rpc.spend_clawback_coins(
910
- SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
911
- )
912
- assert len(resp.transaction_ids) == 0
913
- # Test missing metadata
914
- await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(dataclasses.replace(coin_record, metadata=None))
915
- resp = await wallet_1_rpc.spend_clawback_coins(
916
- SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
917
- )
918
- assert len(resp.transaction_ids) == 0
919
- # Test missing incoming tx
920
- coin_record = await wallet_1_node.wallet_state_manager.coin_store.get_coin_record(clawback_coin_id_2)
921
- assert coin_record is not None
922
- fake_coin = Coin(coin_record.coin.parent_coin_info, wallet_2_puzhash, coin_record.coin.amount)
923
- await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
924
- dataclasses.replace(coin_record, coin=fake_coin)
925
- )
926
- resp = await wallet_1_rpc.spend_clawback_coins(
927
- SpendClawbackCoins(coin_ids=[fake_coin.name()], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
928
- )
929
- assert resp.transaction_ids == []
930
- # Test coin puzzle hash doesn't match the puzzle
931
- farmed_tx = (await wallet_1.wallet_state_manager.tx_store.get_farming_rewards())[0]
932
- await wallet_1.wallet_state_manager.tx_store.add_transaction_record(
933
- dataclasses.replace(farmed_tx, name=fake_coin.name())
934
- )
935
- await wallet_1_node.wallet_state_manager.coin_store.add_coin_record(
936
- dataclasses.replace(coin_record, coin=fake_coin)
937
- )
938
- resp = await wallet_1_rpc.spend_clawback_coins(
939
- SpendClawbackCoins(coin_ids=[fake_coin.name()], fee=uint64(100), push=True), tx_config=DEFAULT_TX_CONFIG
940
- )
941
- assert resp.transaction_ids == []
942
- # Test claim spend
943
- await wallet_2_rpc.set_auto_claim(
944
- AutoClaimSettings(
945
- enabled=False,
946
- tx_fee=uint64(100),
947
- min_amount=uint64(0),
948
- batch_size=uint16(1),
949
- )
950
- )
951
- resp = await wallet_2_rpc.spend_clawback_coins(
952
- SpendClawbackCoins(coin_ids=[clawback_coin_id_1, clawback_coin_id_2], fee=uint64(100), push=True),
953
- tx_config=DEFAULT_TX_CONFIG,
954
- )
955
- assert len(resp.transaction_ids) == 2
956
- for clawback_tx in resp.transactions:
957
- if clawback_tx.spend_bundle is not None:
958
- await time_out_assert_not_none(
959
- 10, full_node_api.full_node.mempool_manager.get_spendbundle, clawback_tx.spend_bundle.name()
960
- )
961
- await farm_transaction_block(full_node_api, wallet_2_node)
962
- await time_out_assert(20, get_confirmed_balance, generated_funds + 300, wallet_2_rpc, 1)
963
- # Test spent coin
964
- resp = await wallet_2_rpc.spend_clawback_coins(
965
- SpendClawbackCoins(coin_ids=[clawback_coin_id_1], fee=uint64(500), push=True), tx_config=DEFAULT_TX_CONFIG
966
- )
967
- assert resp.transaction_ids == []
968
-
969
-
970
- @pytest.mark.anyio
971
- async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
972
- env: WalletRpcTestEnvironment = wallet_rpc_environment
902
+ async def test_send_transaction_multi(wallet_environments: WalletTestFramework) -> None:
903
+ env = wallet_environments.environments[0]
904
+ env_2 = wallet_environments.environments[1]
973
905
 
974
- wallet_2: Wallet = env.wallet_2.wallet
975
- wallet_node: WalletNode = env.wallet_1.node
976
- full_node_api: FullNodeSimulator = env.full_node.api
977
- client: WalletRpcClient = env.wallet_1.rpc_client
906
+ wallet_2: Wallet = env_2.xch_wallet
907
+ wallet_node: WalletNode = env.node
908
+ full_node_api: FullNodeSimulator = wallet_environments.full_node
909
+ client: WalletRpcClient = env.rpc_client
978
910
 
979
- generated_funds = await generate_funds(full_node_api, env.wallet_1)
911
+ INITIAL_BALANCE = await env.xch_wallet.get_confirmed_balance()
980
912
 
981
913
  select_coins_response = await client.select_coins(
982
914
  SelectCoins.from_coin_selection_config(
983
- amount=uint64(1750000000000), wallet_id=uint32(1), coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG
915
+ amount=uint64(1750000000000),
916
+ wallet_id=uint32(1),
917
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config,
984
918
  )
985
919
  ) # we want a coin that won't be selected by default
986
- outputs = await create_tx_outputs(wallet_2, [(uint64(1), ["memo_1"]), (uint64(2), ["memo_2"])])
987
- amount_outputs = sum(output["amount"] for output in outputs)
920
+ outputs = await create_tx_outputs(
921
+ wallet_2, wallet_environments.tx_config, [(uint64(1), ["memo_1"]), (uint64(2), ["memo_2"])]
922
+ )
923
+ amount_outputs = sum(output.amount for output in outputs)
988
924
  amount_fee = uint64(amount_outputs + 1)
989
925
 
990
926
  send_tx_res: TransactionRecord = (
991
927
  await client.send_transaction_multi(
992
- 1,
993
- outputs,
994
- DEFAULT_TX_CONFIG,
995
- coins=select_coins_response.coins,
996
- fee=amount_fee,
928
+ SendTransactionMulti(
929
+ wallet_id=uint32(1),
930
+ additions=outputs,
931
+ coins=select_coins_response.coins,
932
+ fee=amount_fee,
933
+ push=True,
934
+ ),
935
+ tx_config=wallet_environments.tx_config,
997
936
  )
998
937
  ).transaction
999
938
  spend_bundle = send_tx_res.spend_bundle
@@ -1005,7 +944,7 @@ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvir
1005
944
 
1006
945
  await farm_transaction(full_node_api, wallet_node, spend_bundle)
1007
946
 
1008
- await time_out_assert(20, get_confirmed_balance, generated_funds - amount_outputs - amount_fee, client, 1)
947
+ await time_out_assert(20, get_confirmed_balance, INITIAL_BALANCE - amount_outputs - amount_fee, client, 1)
1009
948
 
1010
949
  # Checks that the memo can be retrieved
1011
950
  tx_confirmed = (await client.get_transaction(GetTransaction(send_tx_res.name))).transaction
@@ -1013,30 +952,39 @@ async def test_send_transaction_multi(wallet_rpc_environment: WalletRpcTestEnvir
1013
952
  memos = tx_confirmed.memos
1014
953
  assert len(memos) == len(outputs)
1015
954
  for output in outputs:
1016
- assert [output["memos"][0].encode()] in memos.values()
955
+ assert output.memos is not None
956
+ assert [output.memos[0].encode()] in memos.values()
1017
957
  spend_bundle = send_tx_res.spend_bundle
1018
958
  assert spend_bundle is not None
1019
959
  for key in memos.keys():
1020
960
  assert key in [a.name() for a in spend_bundle.additions()]
1021
961
 
1022
962
 
963
+ @pytest.mark.parametrize(
964
+ "wallet_environments",
965
+ [{"num_environments": 1, "blocks_needed": [3]}],
966
+ indirect=True,
967
+ )
968
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1023
969
  @pytest.mark.anyio
1024
- async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
1025
- env: WalletRpcTestEnvironment = wallet_rpc_environment
1026
-
1027
- wallet: Wallet = env.wallet_1.wallet
1028
- wallet_node: WalletNode = env.wallet_1.node
1029
- full_node_api: FullNodeSimulator = env.full_node.api
1030
- client: WalletRpcClient = env.wallet_1.rpc_client
970
+ async def test_get_transactions(wallet_environments: WalletTestFramework) -> None:
971
+ env = wallet_environments.environments[0]
1031
972
 
1032
- await generate_funds(full_node_api, env.wallet_1, 5)
973
+ wallet: Wallet = env.xch_wallet
974
+ wallet_node: WalletNode = env.node
975
+ full_node_api: FullNodeSimulator = wallet_environments.full_node
976
+ client: WalletRpcClient = env.rpc_client
1033
977
 
1034
978
  all_transactions = (await client.get_transactions(GetTransactions(uint32(1)))).transactions
1035
- assert len(all_transactions) >= 10
979
+ initially_farmed_blocks = 3
980
+ # We expect 2 transactions per farmed block
981
+ expected_initial_txs_count = initially_farmed_blocks * 2
982
+ unconfirmed_txs_count = 0
983
+ assert len(all_transactions) == expected_initial_txs_count
1036
984
  # Test transaction pagination
1037
- some_transactions = (await client.get_transactions(GetTransactions(uint32(1), uint16(0), uint16(5)))).transactions
985
+ some_transactions = (await client.get_transactions(GetTransactions(uint32(1), uint32(0), uint32(5)))).transactions
1038
986
  some_transactions_2 = (
1039
- await client.get_transactions(GetTransactions(uint32(1), uint16(5), uint16(10)))
987
+ await client.get_transactions(GetTransactions(uint32(1), uint32(5), uint32(10)))
1040
988
  ).transactions
1041
989
  assert some_transactions == all_transactions[0:5]
1042
990
  assert some_transactions_2 == all_transactions[5:10]
@@ -1048,13 +996,14 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
1048
996
  assert all_transactions == sorted(all_transactions, key=attrgetter("confirmed_at_height"), reverse=True)
1049
997
 
1050
998
  # Test RELEVANCE
1051
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
999
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1052
1000
  puzhash = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
1053
1001
  await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
1054
1002
  await client.send_transaction(
1055
1003
  SendTransaction(wallet_id=uint32(1), amount=uint64(1), address=encode_puzzle_hash(puzhash, "txch"), push=True),
1056
- DEFAULT_TX_CONFIG,
1004
+ wallet_environments.tx_config,
1057
1005
  ) # Create a pending tx
1006
+ unconfirmed_txs_count += 1
1058
1007
 
1059
1008
  with pytest.raises(ValueError, match="There is no known sort foo"):
1060
1009
  await client.get_transactions(GetTransactions(uint32(1), sort_key="foo"))
@@ -1076,20 +1025,25 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
1076
1025
  assert all_transactions == sorted_transactions
1077
1026
 
1078
1027
  # Test get_transactions to address
1079
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1028
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1080
1029
  ph_by_addr = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
1081
1030
  await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
1082
1031
  await client.send_transaction(
1083
1032
  SendTransaction(
1084
1033
  wallet_id=uint32(1), amount=uint64(1), address=encode_puzzle_hash(ph_by_addr, "txch"), push=True
1085
1034
  ),
1086
- DEFAULT_TX_CONFIG,
1035
+ wallet_environments.tx_config,
1087
1036
  )
1037
+ unconfirmed_txs_count += 1
1088
1038
  await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
1089
1039
  tx_for_address = (
1090
1040
  await client.get_transactions(GetTransactions(uint32(1), to_address=encode_puzzle_hash(ph_by_addr, "txch")))
1091
1041
  ).transactions
1092
- assert len(tx_for_address) == 1
1042
+ assert (
1043
+ len(tx_for_address) == expected_initial_txs_count + unconfirmed_txs_count
1044
+ if wallet_environments.tx_config.reuse_puzhash
1045
+ else 1
1046
+ )
1093
1047
  assert tx_for_address[0].to_puzzle_hash == ph_by_addr
1094
1048
 
1095
1049
  # Test type filter
@@ -1098,14 +1052,15 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
1098
1052
  GetTransactions(uint32(1), type_filter=TransactionTypeFilter.include([TransactionType.COINBASE_REWARD]))
1099
1053
  )
1100
1054
  ).transactions
1101
- assert len(all_transactions) == 5
1055
+ # Each farmed block creates one COINBASE_REWARD transaction
1056
+ assert len(all_transactions) == initially_farmed_blocks
1102
1057
  assert all(transaction.type == TransactionType.COINBASE_REWARD.value for transaction in all_transactions)
1103
1058
  # Test confirmed filter
1104
1059
  all_transactions = (await client.get_transactions(GetTransactions(uint32(1), confirmed=True))).transactions
1105
- assert len(all_transactions) == 10
1060
+ assert len(all_transactions) == expected_initial_txs_count
1106
1061
  assert all(transaction.confirmed for transaction in all_transactions)
1107
1062
  all_transactions = (await client.get_transactions(GetTransactions(uint32(1), confirmed=False))).transactions
1108
- assert len(all_transactions) == 2
1063
+ assert len(all_transactions) == unconfirmed_txs_count
1109
1064
  assert all(not transaction.confirmed for transaction in all_transactions)
1110
1065
 
1111
1066
  # Test bypass broken txs
@@ -1124,14 +1079,16 @@ async def test_get_transactions(wallet_rpc_environment: WalletRpcTestEnvironment
1124
1079
  assert len(all_transactions) == 1
1125
1080
 
1126
1081
 
1082
+ @pytest.mark.parametrize(
1083
+ "wallet_environments",
1084
+ [{"num_environments": 1, "blocks_needed": [1]}],
1085
+ indirect=True,
1086
+ )
1087
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1127
1088
  @pytest.mark.anyio
1128
- async def test_get_transaction_count(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
1129
- env: WalletRpcTestEnvironment = wallet_rpc_environment
1130
-
1131
- full_node_api: FullNodeSimulator = env.full_node.api
1132
- client: WalletRpcClient = env.wallet_1.rpc_client
1133
-
1134
- await generate_funds(full_node_api, env.wallet_1)
1089
+ async def test_get_transaction_count(wallet_environments: WalletTestFramework) -> None:
1090
+ env = wallet_environments.environments[0]
1091
+ client: WalletRpcClient = env.rpc_client
1135
1092
 
1136
1093
  all_transactions = (await client.get_transactions(GetTransactions(uint32(1)))).transactions
1137
1094
  assert len(all_transactions) > 0
@@ -1213,7 +1170,7 @@ async def test_cat_endpoints(wallet_environments: WalletTestFramework, wallet_ty
1213
1170
  asset_id = (await env_0.rpc_client.get_cat_asset_id(CATGetAssetID(cat_0_id))).asset_id
1214
1171
  assert (
1215
1172
  await env_0.rpc_client.get_cat_name(CATGetName(cat_0_id))
1216
- ).name == wallet_type.default_wallet_name_for_unknown_cat(asset_id.hex())
1173
+ ).name == wallet_type.default_wallet_name_for_unknown_cat(asset_id)
1217
1174
  await env_0.rpc_client.set_cat_name(CATSetName(cat_0_id, "My cat"))
1218
1175
  assert (await env_0.rpc_client.get_cat_name(CATGetName(cat_0_id))).name == "My cat"
1219
1176
  asset_to_name_response = await env_0.rpc_client.cat_asset_id_to_name(CATAssetIDToName(asset_id))
@@ -1229,10 +1186,17 @@ async def test_cat_endpoints(wallet_environments: WalletTestFramework, wallet_ty
1229
1186
  assert asset_to_name_response.name == next(iter(DEFAULT_CATS.items()))[1]["name"]
1230
1187
 
1231
1188
  # Creates a second wallet with the same CAT
1232
- res = await env_1.rpc_client.create_wallet_for_existing_cat(asset_id)
1233
- assert res["success"]
1234
- cat_1_id = res["wallet_id"]
1235
- cat_1_asset_id = bytes.fromhex(res["asset_id"])
1189
+ create_wallet_res = await env_1.rpc_client.create_new_wallet(
1190
+ CreateNewWallet(
1191
+ wallet_type=CreateNewWalletType.CAT_WALLET,
1192
+ mode=WalletCreationMode.EXISTING,
1193
+ asset_id=asset_id,
1194
+ push=True,
1195
+ ),
1196
+ tx_config=wallet_environments.tx_config,
1197
+ )
1198
+ cat_1_id = create_wallet_res.wallet_id
1199
+ cat_1_asset_id = create_wallet_res.asset_id
1236
1200
  assert cat_1_asset_id == asset_id
1237
1201
 
1238
1202
  await wallet_environments.process_pending_states(
@@ -1525,12 +1489,21 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
1525
1489
  cat_asset_id = cat_wallet.cat_info.limitations_program_hash
1526
1490
 
1527
1491
  # Creates a wallet for the same CAT on wallet_2 and send 4 CAT from wallet_1 to it
1528
- await env_2.rpc_client.create_wallet_for_existing_cat(cat_asset_id)
1492
+ await env_2.rpc_client.create_new_wallet(
1493
+ CreateNewWallet(
1494
+ wallet_type=CreateNewWalletType.CAT_WALLET,
1495
+ mode=WalletCreationMode.EXISTING,
1496
+ asset_id=cat_asset_id,
1497
+ push=True,
1498
+ ),
1499
+ tx_config=wallet_environments.tx_config,
1500
+ )
1529
1501
  wallet_2_address = (await env_2.rpc_client.get_next_address(GetNextAddress(cat_wallet_id, False))).address
1530
- adds = [{"puzzle_hash": decode_puzzle_hash(wallet_2_address), "amount": uint64(4), "memos": ["the cat memo"]}]
1502
+ adds = [Addition(puzzle_hash=decode_puzzle_hash(wallet_2_address), amount=uint64(4), memos=["the cat memo"])]
1531
1503
  tx_res = (
1532
1504
  await env_1.rpc_client.send_transaction_multi(
1533
- cat_wallet_id, additions=adds, tx_config=wallet_environments.tx_config, fee=uint64(0)
1505
+ SendTransactionMulti(wallet_id=uint32(cat_wallet_id), additions=adds, fee=uint64(0), push=True),
1506
+ tx_config=wallet_environments.tx_config,
1534
1507
  )
1535
1508
  ).transaction
1536
1509
  spend_bundle = tx_res.spend_bundle
@@ -1586,56 +1559,54 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
1586
1559
  )
1587
1560
  # Create an offer of 5 chia for one CAT
1588
1561
  await env_1.rpc_client.create_offer_for_ids(
1589
- {uint32(1): -5, cat_asset_id.hex(): 1}, wallet_environments.tx_config, validate_only=True
1562
+ CreateOfferForIDs(offer={str(1): "-5", cat_asset_id.hex(): "1"}, validate_only=True),
1563
+ tx_config=wallet_environments.tx_config,
1590
1564
  )
1591
- all_offers = await env_1.rpc_client.get_all_offers()
1565
+ all_offers = (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1592
1566
  assert len(all_offers) == 0
1593
1567
 
1594
- driver_dict: dict[str, Any] = {
1595
- cat_asset_id.hex(): {
1596
- "type": "CAT",
1597
- "tail": "0x" + cat_asset_id.hex(),
1598
- **(
1599
- {}
1600
- if wallet_type is CATWallet
1601
- else {"also": {"type": "revocation layer", "hidden_puzzle_hash": "0x" + bytes32.zeros.hex()}}
1602
- ),
1603
- }
1568
+ driver_dict = {
1569
+ cat_asset_id: PuzzleInfo(
1570
+ {
1571
+ "type": "CAT",
1572
+ "tail": "0x" + cat_asset_id.hex(),
1573
+ **(
1574
+ {}
1575
+ if wallet_type is CATWallet
1576
+ else {"also": {"type": "revocation layer", "hidden_puzzle_hash": "0x" + bytes32.zeros.hex()}}
1577
+ ),
1578
+ }
1579
+ )
1604
1580
  }
1605
1581
 
1606
1582
  create_res = await env_1.rpc_client.create_offer_for_ids(
1607
- {uint32(1): -5, cat_asset_id.hex(): 1},
1608
- wallet_environments.tx_config,
1609
- driver_dict=driver_dict,
1610
- fee=uint64(1),
1583
+ CreateOfferForIDs(offer={str(1): "-5", cat_asset_id.hex(): "1"}, driver_dict=driver_dict, fee=uint64(1)),
1584
+ tx_config=wallet_environments.tx_config,
1611
1585
  )
1612
1586
  offer = create_res.offer
1613
1587
 
1614
- id, summary = await env_1.rpc_client.get_offer_summary(offer)
1615
- assert id == offer.name()
1616
- id, advanced_summary = await env_1.rpc_client.get_offer_summary(offer, advanced=True)
1617
- assert id == offer.name()
1618
- assert summary == {
1619
- "offered": {"xch": 5},
1620
- "requested": {cat_asset_id.hex(): 1},
1621
- "infos": driver_dict,
1622
- "fees": 1,
1623
- "additions": [c.name().hex() for c in offer.additions()],
1624
- "removals": [c.name().hex() for c in offer.removals()],
1625
- "valid_times": {
1626
- "max_height": None,
1627
- "max_time": None,
1628
- "min_height": None,
1629
- "min_time": None,
1630
- },
1631
- }
1632
- assert advanced_summary == summary
1588
+ offer_summary_response = await env_1.rpc_client.get_offer_summary(GetOfferSummary(offer.to_bech32()))
1589
+ assert offer_summary_response.id == offer.name()
1590
+ offer_summary_response_advanced = await env_1.rpc_client.get_offer_summary(
1591
+ GetOfferSummary(offer.to_bech32(), advanced=True)
1592
+ )
1593
+ assert offer_summary_response_advanced.id == offer.name()
1594
+ assert offer_summary_response_advanced.summary == OfferSummary(
1595
+ offered={"xch": "5"},
1596
+ requested={cat_asset_id.hex(): "1"},
1597
+ infos={key.hex(): info for key, info in driver_dict.items()},
1598
+ fees=uint64(1),
1599
+ additions=[c.name() for c in offer.additions()],
1600
+ removals=[c.name() for c in offer.removals()],
1601
+ valid_times=ConditionValidTimesAbsolute(),
1602
+ )
1603
+ assert offer_summary_response_advanced.summary == offer_summary_response.summary
1633
1604
 
1634
1605
  offer_validity_response = await env_1.rpc_client.check_offer_validity(CheckOfferValidity(offer.to_bech32()))
1635
1606
  assert offer_validity_response.id == offer.name()
1636
1607
  assert offer_validity_response.valid
1637
1608
 
1638
- all_offers = await env_1.rpc_client.get_all_offers(file_contents=True)
1609
+ all_offers = (await env_1.rpc_client.get_all_offers(GetAllOffers(file_contents=True))).trade_records
1639
1610
  assert len(all_offers) == 1
1640
1611
  assert TradeStatus(all_offers[0].status) == TradeStatus.PENDING_ACCEPT
1641
1612
  assert all_offers[0].offer == bytes(offer)
@@ -1645,26 +1616,44 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
1645
1616
  assert offer_count.my_offers_count == 1
1646
1617
  assert offer_count.taken_offers_count == 0
1647
1618
 
1648
- trade_record = (await env_2.rpc_client.take_offer(offer, wallet_environments.tx_config, fee=uint64(1))).trade_record
1619
+ trade_record = (
1620
+ await env_2.rpc_client.take_offer(
1621
+ TakeOffer(
1622
+ offer=offer.to_bech32(),
1623
+ fee=uint64(1),
1624
+ push=True,
1625
+ ),
1626
+ wallet_environments.tx_config,
1627
+ )
1628
+ ).trade_record
1649
1629
  assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CONFIRM
1650
1630
 
1651
- await env_1.rpc_client.cancel_offer(offer.name(), wallet_environments.tx_config, secure=False)
1652
-
1653
- trade_record = await env_1.rpc_client.get_offer(offer.name(), file_contents=True)
1654
- assert trade_record.offer == bytes(offer)
1655
- assert TradeStatus(trade_record.status) == TradeStatus.CANCELLED
1631
+ await env_1.rpc_client.cancel_offer(
1632
+ CancelOffer(
1633
+ trade_id=offer.name(),
1634
+ secure=False,
1635
+ push=True,
1636
+ ),
1637
+ tx_config=wallet_environments.tx_config,
1638
+ )
1639
+
1640
+ trade_record = (await env_1.rpc_client.get_offer(GetOffer(offer.name(), file_contents=True))).trade_record
1641
+ assert trade_record.offer == bytes(offer)
1642
+ assert TradeStatus(trade_record.status) == TradeStatus.CANCELLED
1656
1643
 
1657
1644
  failed_cancel_res = await env_1.rpc_client.cancel_offer(
1658
- offer.name(), wallet_environments.tx_config, fee=uint64(1), secure=True
1645
+ CancelOffer(trade_id=offer.name(), fee=uint64(1), secure=True, push=True),
1646
+ tx_config=wallet_environments.tx_config,
1659
1647
  )
1660
1648
 
1661
- trade_record = await env_1.rpc_client.get_offer(offer.name())
1649
+ trade_record = (await env_1.rpc_client.get_offer(GetOffer(offer.name()))).trade_record
1662
1650
  assert TradeStatus(trade_record.status) == TradeStatus.PENDING_CANCEL
1663
1651
 
1664
1652
  create_res = await env_1.rpc_client.create_offer_for_ids(
1665
- {uint32(1): -5, cat_wallet_id: 1}, wallet_environments.tx_config, fee=uint64(1)
1653
+ CreateOfferForIDs(offer={str(1): "-5", str(cat_wallet_id): "1"}, fee=uint64(1)),
1654
+ tx_config=wallet_environments.tx_config,
1666
1655
  )
1667
- all_offers = await env_1.rpc_client.get_all_offers()
1656
+ all_offers = (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1668
1657
  assert len(all_offers) == 2
1669
1658
  offer_count = await env_1.rpc_client.get_offers_count()
1670
1659
  assert offer_count.total == 2
@@ -1744,7 +1733,7 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
1744
1733
  )
1745
1734
 
1746
1735
  async def is_trade_confirmed(client: WalletRpcClient, offer: Offer) -> bool:
1747
- trade_record = await client.get_offer(offer.name())
1736
+ trade_record = (await client.get_offer(GetOffer(offer.name()))).trade_record
1748
1737
  return TradeStatus(trade_record.status) == TradeStatus.CONFIRMED
1749
1738
 
1750
1739
  await time_out_assert(15, is_trade_confirmed, True, env_1.rpc_client, offer)
@@ -1753,39 +1742,64 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
1753
1742
  def only_ids(trades: list[TradeRecord]) -> list[bytes32]:
1754
1743
  return [t.trade_id for t in trades]
1755
1744
 
1756
- trade_record = await env_1.rpc_client.get_offer(offer.name())
1757
- all_offers = await env_1.rpc_client.get_all_offers(include_completed=True) # confirmed at index descending
1745
+ trade_record = (await env_1.rpc_client.get_offer(GetOffer(offer.name()))).trade_record
1746
+ all_offers = ( # confirmed at index descending
1747
+ await env_1.rpc_client.get_all_offers(GetAllOffers(include_completed=True))
1748
+ ).trade_records
1758
1749
  assert len(all_offers) == 2
1759
1750
  assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
1760
- all_offers = await env_1.rpc_client.get_all_offers(
1761
- include_completed=True, reverse=True
1762
- ) # confirmed at index ascending
1751
+ all_offers = ( # confirmed at index ascending
1752
+ await env_1.rpc_client.get_all_offers(GetAllOffers(include_completed=True, reverse=True))
1753
+ ).trade_records
1763
1754
  assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
1764
- all_offers = await env_1.rpc_client.get_all_offers(include_completed=True, sort_key="RELEVANCE") # most relevant
1755
+ all_offers = ( # most relevant
1756
+ await env_1.rpc_client.get_all_offers(GetAllOffers(include_completed=True, sort_key="RELEVANCE"))
1757
+ ).trade_records
1765
1758
  assert only_ids(all_offers) == only_ids([new_trade_record, trade_record])
1766
- all_offers = await env_1.rpc_client.get_all_offers(
1767
- include_completed=True, sort_key="RELEVANCE", reverse=True
1768
- ) # least relevant
1759
+ all_offers = ( # least relevant
1760
+ await env_1.rpc_client.get_all_offers(GetAllOffers(include_completed=True, sort_key="RELEVANCE", reverse=True))
1761
+ ).trade_records
1769
1762
  assert only_ids(all_offers) == only_ids([trade_record, new_trade_record])
1770
1763
  # Test pagination
1771
- all_offers = await env_1.rpc_client.get_all_offers(include_completed=True, start=0, end=1)
1764
+ all_offers = (
1765
+ await env_1.rpc_client.get_all_offers(GetAllOffers(include_completed=True, start=uint16(0), end=uint16(1)))
1766
+ ).trade_records
1772
1767
  assert len(all_offers) == 1
1773
- all_offers = await env_1.rpc_client.get_all_offers(include_completed=True, start=50)
1768
+ all_offers = (
1769
+ await env_1.rpc_client.get_all_offers(GetAllOffers(include_completed=True, start=uint16(10)))
1770
+ ).trade_records
1774
1771
  assert len(all_offers) == 0
1775
- all_offers = await env_1.rpc_client.get_all_offers(include_completed=True, start=0, end=50)
1772
+ all_offers = (
1773
+ await env_1.rpc_client.get_all_offers(GetAllOffers(include_completed=True, start=uint16(0), end=uint16(50)))
1774
+ ).trade_records
1776
1775
  assert len(all_offers) == 2
1777
1776
 
1778
1777
  await env_1.rpc_client.create_offer_for_ids(
1779
- {uint32(1): -5, cat_asset_id.hex(): 1},
1780
- wallet_environments.tx_config,
1781
- driver_dict=driver_dict,
1778
+ CreateOfferForIDs(offer={str(1): "-5", cat_asset_id.hex(): "1"}, driver_dict=driver_dict),
1779
+ tx_config=wallet_environments.tx_config,
1782
1780
  )
1783
1781
  assert (
1784
- len([o for o in await env_1.rpc_client.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 2
1782
+ len(
1783
+ [
1784
+ o
1785
+ for o in (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1786
+ if o.status == TradeStatus.PENDING_ACCEPT.value
1787
+ ]
1788
+ )
1789
+ == 2
1790
+ )
1791
+ await env_1.rpc_client.cancel_offers(
1792
+ CancelOffers(secure=True, batch_size=uint16(1), push=True), tx_config=wallet_environments.tx_config
1785
1793
  )
1786
- await env_1.rpc_client.cancel_offers(wallet_environments.tx_config, batch_size=1)
1787
1794
  assert (
1788
- len([o for o in await env_1.rpc_client.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 0
1795
+ len(
1796
+ [
1797
+ o
1798
+ for o in (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1799
+ if o.status == TradeStatus.PENDING_ACCEPT.value
1800
+ ]
1801
+ )
1802
+ == 0
1789
1803
  )
1790
1804
  await wallet_environments.process_pending_states(
1791
1805
  [
@@ -1814,21 +1828,35 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
1814
1828
  )
1815
1829
 
1816
1830
  await env_1.rpc_client.create_offer_for_ids(
1817
- {uint32(1): -5, cat_asset_id.hex(): 1},
1818
- wallet_environments.tx_config,
1819
- driver_dict=driver_dict,
1831
+ CreateOfferForIDs(offer={str(1): "-5", cat_asset_id.hex(): "1"}, driver_dict=driver_dict),
1832
+ tx_config=wallet_environments.tx_config,
1820
1833
  )
1821
1834
  await env_1.rpc_client.create_offer_for_ids(
1822
- {uint32(1): 5, cat_asset_id.hex(): -1},
1823
- wallet_environments.tx_config,
1824
- driver_dict=driver_dict,
1835
+ CreateOfferForIDs(offer={str(1): "5", cat_asset_id.hex(): "-1"}, driver_dict=driver_dict),
1836
+ tx_config=wallet_environments.tx_config,
1825
1837
  )
1826
1838
  assert (
1827
- len([o for o in await env_1.rpc_client.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 2
1839
+ len(
1840
+ [
1841
+ o
1842
+ for o in (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1843
+ if o.status == TradeStatus.PENDING_ACCEPT.value
1844
+ ]
1845
+ )
1846
+ == 2
1847
+ )
1848
+ await env_1.rpc_client.cancel_offers(
1849
+ CancelOffers(secure=True, cancel_all=True, push=True), tx_config=wallet_environments.tx_config
1828
1850
  )
1829
- await env_1.rpc_client.cancel_offers(wallet_environments.tx_config, cancel_all=True)
1830
1851
  assert (
1831
- len([o for o in await env_1.rpc_client.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 0
1852
+ len(
1853
+ [
1854
+ o
1855
+ for o in (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1856
+ if o.status == TradeStatus.PENDING_ACCEPT.value
1857
+ ]
1858
+ )
1859
+ == 0
1832
1860
  )
1833
1861
 
1834
1862
  await wallet_environments.process_pending_states(
@@ -1868,51 +1896,81 @@ async def test_offer_endpoints(wallet_environments: WalletTestFramework, wallet_
1868
1896
  )
1869
1897
 
1870
1898
  await env_1.rpc_client.create_offer_for_ids(
1871
- {uint32(1): 5, cat_asset_id.hex(): -1},
1872
- wallet_environments.tx_config,
1873
- driver_dict=driver_dict,
1899
+ CreateOfferForIDs(offer={str(1): "5", cat_asset_id.hex(): "-1"}, driver_dict=driver_dict),
1900
+ tx_config=wallet_environments.tx_config,
1874
1901
  )
1875
1902
  assert (
1876
- len([o for o in await env_1.rpc_client.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 1
1903
+ len(
1904
+ [
1905
+ o
1906
+ for o in (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1907
+ if o.status == TradeStatus.PENDING_ACCEPT.value
1908
+ ]
1909
+ )
1910
+ == 1
1911
+ )
1912
+ await env_1.rpc_client.cancel_offers(
1913
+ CancelOffers(secure=True, asset_id=bytes32.zeros.hex(), push=True), tx_config=wallet_environments.tx_config
1877
1914
  )
1878
- await env_1.rpc_client.cancel_offers(wallet_environments.tx_config, asset_id=bytes32.zeros)
1879
1915
  assert (
1880
- len([o for o in await env_1.rpc_client.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 1
1916
+ len(
1917
+ [
1918
+ o
1919
+ for o in (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1920
+ if o.status == TradeStatus.PENDING_ACCEPT.value
1921
+ ]
1922
+ )
1923
+ == 1
1924
+ )
1925
+ await env_1.rpc_client.cancel_offers(
1926
+ CancelOffers(secure=True, asset_id=cat_asset_id.hex(), push=True), tx_config=wallet_environments.tx_config
1881
1927
  )
1882
- await env_1.rpc_client.cancel_offers(wallet_environments.tx_config, asset_id=cat_asset_id)
1883
1928
  assert (
1884
- len([o for o in await env_1.rpc_client.get_all_offers() if o.status == TradeStatus.PENDING_ACCEPT.value]) == 0
1929
+ len(
1930
+ [
1931
+ o
1932
+ for o in (await env_1.rpc_client.get_all_offers(GetAllOffers())).trade_records
1933
+ if o.status == TradeStatus.PENDING_ACCEPT.value
1934
+ ]
1935
+ )
1936
+ == 0
1885
1937
  )
1886
1938
 
1887
1939
  with pytest.raises(ValueError, match="not currently supported"):
1888
1940
  await env_1.rpc_client.create_offer_for_ids(
1889
- {uint32(1): -5, cat_asset_id.hex(): 1},
1941
+ CreateOfferForIDs(
1942
+ offer={str(1): "-5", cat_asset_id.hex(): "1"},
1943
+ driver_dict=driver_dict,
1944
+ ),
1890
1945
  wallet_environments.tx_config,
1891
- driver_dict=driver_dict,
1892
1946
  timelock_info=ConditionValidTimes(min_secs_since_created=uint64(1)),
1893
1947
  )
1894
1948
 
1895
1949
 
1950
+ @pytest.mark.parametrize(
1951
+ "wallet_environments",
1952
+ [{"num_environments": 1, "blocks_needed": [5]}],
1953
+ indirect=True,
1954
+ )
1955
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1896
1956
  @pytest.mark.anyio
1897
- async def test_get_coin_records_by_names(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
1898
- env: WalletRpcTestEnvironment = wallet_rpc_environment
1899
- wallet_node: WalletNode = env.wallet_1.node
1900
- client: WalletRpcClient = env.wallet_1.rpc_client
1957
+ async def test_get_coin_records_by_names(wallet_environments: WalletTestFramework) -> None:
1958
+ env = wallet_environments.environments[0]
1959
+ wallet_node: WalletNode = env.node
1960
+ client: WalletRpcClient = env.rpc_client
1901
1961
  store = wallet_node.wallet_state_manager.coin_store
1902
- full_node_api = env.full_node.api
1903
- # Generate some funds
1904
- generated_funds = await generate_funds(full_node_api, env.wallet_1, 5)
1905
- async with env.wallet_1.wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
1906
- address = encode_puzzle_hash(
1907
- await action_scope.get_puzzle_hash(env.wallet_1.wallet.wallet_state_manager), "txch"
1908
- )
1962
+ full_node_api = wallet_environments.full_node
1963
+
1964
+ INITIAL_BALANCE = await env.xch_wallet.get_confirmed_balance()
1965
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1966
+ address = encode_puzzle_hash(await action_scope.get_puzzle_hash(env.wallet_state_manager), "txch")
1909
1967
  await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
1910
1968
 
1911
1969
  # Spend half of it back to the same wallet get some spent coins in the wallet
1912
1970
  tx = (
1913
1971
  await client.send_transaction(
1914
- SendTransaction(wallet_id=uint32(1), amount=uint64(generated_funds / 2), address=address, push=True),
1915
- DEFAULT_TX_CONFIG,
1972
+ SendTransaction(wallet_id=uint32(1), amount=uint64(INITIAL_BALANCE / 2), address=address, push=True),
1973
+ wallet_environments.tx_config,
1916
1974
  )
1917
1975
  ).transaction
1918
1976
  assert tx.spend_bundle is not None
@@ -1958,31 +2016,55 @@ async def test_get_coin_records_by_names(wallet_rpc_environment: WalletRpcTestEn
1958
2016
  await client.get_coin_records_by_names(GetCoinRecordsByNames(coin_ids, include_spent_coins=False))
1959
2017
 
1960
2018
 
2019
+ @pytest.mark.parametrize(
2020
+ "wallet_environments",
2021
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
2022
+ indirect=True,
2023
+ )
2024
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
1961
2025
  @pytest.mark.anyio
1962
- async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
1963
- env: WalletRpcTestEnvironment = wallet_rpc_environment
1964
-
1965
- wallet_1: Wallet = env.wallet_1.wallet
1966
- wallet_2: Wallet = env.wallet_2.wallet
1967
- wallet_1_node: WalletNode = env.wallet_1.node
1968
- wallet_2_node: WalletNode = env.wallet_2.node
1969
- wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
1970
- wallet_2_rpc: WalletRpcClient = env.wallet_2.rpc_client
1971
- full_node_api: FullNodeSimulator = env.full_node.api
1972
- wallet_1_id = wallet_1.id()
2026
+ async def test_did_endpoints(wallet_environments: WalletTestFramework) -> None:
2027
+ env = wallet_environments.environments[0]
2028
+ env_2 = wallet_environments.environments[1]
2029
+
2030
+ env.wallet_aliases = {
2031
+ "xch": 1,
2032
+ "did": 2,
2033
+ "nft": 3,
2034
+ }
2035
+ env_2.wallet_aliases = {
2036
+ "xch": 1,
2037
+ "did": 2,
2038
+ }
1973
2039
 
1974
- await generate_funds(env.full_node.api, env.wallet_1, 5)
2040
+ wallet_1: Wallet = env.xch_wallet
2041
+ wallet_2: Wallet = env_2.xch_wallet
2042
+ wallet_1_node: WalletNode = env.node
2043
+ wallet_2_node: WalletNode = env_2.node
2044
+ wallet_1_rpc: WalletRpcClient = env.rpc_client
2045
+ wallet_2_rpc: WalletRpcClient = env_2.rpc_client
2046
+ wallet_1_id = wallet_1.id()
1975
2047
 
1976
2048
  # Create a DID wallet
1977
- res = await wallet_1_rpc.create_new_did_wallet(amount=1, tx_config=DEFAULT_TX_CONFIG, name="Profile 1")
1978
- assert res["success"]
1979
- did_wallet_id_0 = res["wallet_id"]
1980
- did_id_0 = res["my_did"]
2049
+ create_new_res = await wallet_1_rpc.create_new_wallet(
2050
+ CreateNewWallet(
2051
+ wallet_type=CreateNewWalletType.DID_WALLET,
2052
+ did_type=DIDType.NEW,
2053
+ amount=uint64(1),
2054
+ wallet_name="Profile 1",
2055
+ push=True,
2056
+ ),
2057
+ tx_config=wallet_environments.tx_config,
2058
+ )
2059
+ did_wallet_id_0 = create_new_res.wallet_id
2060
+ did_id_0 = create_new_res.my_did
2061
+ await env.change_balances({"did": {"init": True, "set_remainder": True}})
2062
+ await env.change_balances({"nft": {"init": True, "set_remainder": True}})
1981
2063
 
1982
2064
  # Get wallet name
1983
2065
  get_name_res = await wallet_1_rpc.did_get_wallet_name(DIDGetWalletName(did_wallet_id_0))
1984
2066
  assert get_name_res.name == "Profile 1"
1985
- nft_wallet = wallet_1_node.wallet_state_manager.wallets[did_wallet_id_0 + 1]
2067
+ nft_wallet = wallet_1_node.wallet_state_manager.wallets[uint32(did_wallet_id_0 + 1)]
1986
2068
  assert isinstance(nft_wallet, NFTWallet)
1987
2069
  assert nft_wallet.get_name() == "Profile 1 NFT Wallet"
1988
2070
 
@@ -2000,36 +2082,80 @@ async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -
2000
2082
  # Create backup file
2001
2083
  await wallet_1_rpc.create_did_backup_file(DIDCreateBackupFile(did_wallet_id_0))
2002
2084
 
2003
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2004
- await farm_transaction_block(full_node_api, wallet_1_node)
2085
+ await wallet_environments.process_pending_states(
2086
+ [
2087
+ WalletStateTransition(
2088
+ pre_block_balance_updates={
2089
+ "xch": {"set_remainder": True},
2090
+ "did": {"set_remainder": True},
2091
+ },
2092
+ post_block_balance_updates={
2093
+ "xch": {"set_remainder": True},
2094
+ "did": {"set_remainder": True},
2095
+ },
2096
+ ),
2097
+ WalletStateTransition(),
2098
+ ]
2099
+ )
2005
2100
 
2006
2101
  # Update metadata
2007
2102
  with pytest.raises(ValueError, match="wallet id 1 is of type Wallet but type DIDWallet is required"):
2008
2103
  await wallet_1_rpc.update_did_metadata(
2009
- DIDUpdateMetadata(wallet_id=wallet_1_id, metadata={"Twitter": "Https://test"}, push=True), DEFAULT_TX_CONFIG
2104
+ DIDUpdateMetadata(wallet_id=wallet_1_id, metadata={"Twitter": "Https://test"}, push=True),
2105
+ wallet_environments.tx_config,
2010
2106
  )
2011
2107
  await wallet_1_rpc.update_did_metadata(
2012
- DIDUpdateMetadata(wallet_id=did_wallet_id_0, metadata={"Twitter": "Https://test"}, push=True), DEFAULT_TX_CONFIG
2108
+ DIDUpdateMetadata(wallet_id=did_wallet_id_0, metadata={"Twitter": "Https://test"}, push=True),
2109
+ wallet_environments.tx_config,
2013
2110
  )
2014
2111
 
2015
2112
  get_metadata_res = await wallet_1_rpc.get_did_metadata(DIDGetMetadata(did_wallet_id_0))
2016
2113
  assert get_metadata_res.metadata["Twitter"] == "Https://test"
2017
2114
 
2018
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2019
- await farm_transaction_block(full_node_api, wallet_1_node)
2115
+ await wallet_environments.process_pending_states(
2116
+ [
2117
+ WalletStateTransition(
2118
+ pre_block_balance_updates={
2119
+ "xch": {"set_remainder": True},
2120
+ "did": {"set_remainder": True},
2121
+ },
2122
+ post_block_balance_updates={
2123
+ "xch": {"set_remainder": True},
2124
+ "did": {"set_remainder": True},
2125
+ },
2126
+ ),
2127
+ WalletStateTransition(),
2128
+ ]
2129
+ )
2020
2130
 
2021
2131
  # Transfer DID
2022
- async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2132
+ async with wallet_2.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2023
2133
  addr = encode_puzzle_hash(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager), "txch")
2024
2134
  await wallet_1_rpc.did_transfer_did(
2025
2135
  DIDTransferDID(
2026
2136
  wallet_id=did_wallet_id_0, inner_address=addr, fee=uint64(0), with_recovery_info=True, push=True
2027
2137
  ),
2028
- DEFAULT_TX_CONFIG,
2138
+ wallet_environments.tx_config,
2029
2139
  )
2030
2140
 
2031
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2032
- await farm_transaction_block(full_node_api, wallet_1_node)
2141
+ await wallet_environments.process_pending_states(
2142
+ [
2143
+ WalletStateTransition(
2144
+ pre_block_balance_updates={
2145
+ "xch": {"set_remainder": True},
2146
+ "did": {"set_remainder": True},
2147
+ },
2148
+ post_block_balance_updates={
2149
+ "xch": {"set_remainder": True},
2150
+ },
2151
+ ),
2152
+ WalletStateTransition(
2153
+ post_block_balance_updates={
2154
+ "did": {"init": True, "set_remainder": True},
2155
+ }
2156
+ ),
2157
+ ]
2158
+ )
2033
2159
 
2034
2160
  async def num_wallets() -> int:
2035
2161
  return len(await wallet_2_node.wallet_state_manager.get_all_wallet_info_entries())
@@ -2052,23 +2178,52 @@ async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -
2052
2178
  assert metadata["Twitter"] == "Https://test"
2053
2179
 
2054
2180
  last_did_coin = await did_wallet_2.get_coin()
2055
- await wallet_2_rpc.did_message_spend(DIDMessageSpend(wallet_id=did_wallet_2.id(), push=True), DEFAULT_TX_CONFIG)
2181
+ await wallet_2_rpc.did_message_spend(
2182
+ DIDMessageSpend(wallet_id=did_wallet_2.id(), push=True), wallet_environments.tx_config
2183
+ )
2056
2184
  await wallet_2_node.wallet_state_manager.add_interested_coin_ids([last_did_coin.name()])
2057
2185
 
2058
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2059
- await farm_transaction_block(full_node_api, wallet_2_node)
2186
+ await wallet_environments.process_pending_states(
2187
+ [
2188
+ WalletStateTransition(),
2189
+ WalletStateTransition(
2190
+ pre_block_balance_updates={
2191
+ "xch": {"set_remainder": True},
2192
+ "did": {"set_remainder": True},
2193
+ },
2194
+ post_block_balance_updates={
2195
+ "xch": {"set_remainder": True},
2196
+ "did": {"set_remainder": True},
2197
+ },
2198
+ ),
2199
+ ]
2200
+ )
2060
2201
 
2061
2202
  next_did_coin = await did_wallet_2.get_coin()
2062
2203
  assert next_did_coin.parent_coin_info == last_did_coin.name()
2063
2204
  last_did_coin = next_did_coin
2064
2205
 
2065
2206
  await wallet_2_rpc.did_message_spend(
2066
- DIDMessageSpend(wallet_id=did_wallet_2.id(), push=True), DEFAULT_TX_CONFIG.override(reuse_puzhash=True)
2207
+ DIDMessageSpend(wallet_id=did_wallet_2.id(), push=True),
2208
+ wallet_environments.tx_config.override(reuse_puzhash=True),
2067
2209
  )
2068
2210
  await wallet_2_node.wallet_state_manager.add_interested_coin_ids([last_did_coin.name()])
2069
2211
 
2070
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2071
- await farm_transaction_block(full_node_api, wallet_2_node)
2212
+ await wallet_environments.process_pending_states(
2213
+ [
2214
+ WalletStateTransition(),
2215
+ WalletStateTransition(
2216
+ pre_block_balance_updates={
2217
+ "xch": {"set_remainder": True},
2218
+ "did": {"set_remainder": True},
2219
+ },
2220
+ post_block_balance_updates={
2221
+ "xch": {"set_remainder": True},
2222
+ "did": {"set_remainder": True},
2223
+ },
2224
+ ),
2225
+ ]
2226
+ )
2072
2227
 
2073
2228
  next_did_coin = await did_wallet_2.get_coin()
2074
2229
  assert next_did_coin.parent_coin_info == last_did_coin.name()
@@ -2079,21 +2234,37 @@ async def test_did_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -
2079
2234
  assert isinstance(pubkey_res.pubkey, G1Element)
2080
2235
 
2081
2236
 
2237
+ @pytest.mark.parametrize(
2238
+ "wallet_environments",
2239
+ [{"num_environments": 2, "blocks_needed": [1, 1]}],
2240
+ indirect=True,
2241
+ )
2242
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2082
2243
  @pytest.mark.anyio
2083
- async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2084
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2085
- wallet_1_node: WalletNode = env.wallet_1.node
2086
- wallet_1_rpc: WalletRpcClient = env.wallet_1.rpc_client
2087
- wallet_2: Wallet = env.wallet_2.wallet
2088
- wallet_2_node: WalletNode = env.wallet_2.node
2089
- wallet_2_rpc: WalletRpcClient = env.wallet_2.rpc_client
2090
- full_node_api: FullNodeSimulator = env.full_node.api
2091
-
2092
- await generate_funds(env.full_node.api, env.wallet_1, 5)
2093
-
2094
- res = await wallet_1_rpc.create_new_nft_wallet(None)
2095
- nft_wallet_id = res["wallet_id"]
2096
- mint_res = await wallet_1_rpc.mint_nft(
2244
+ async def test_nft_endpoints(wallet_environments: WalletTestFramework) -> None:
2245
+ env = wallet_environments.environments[0]
2246
+ env_2 = wallet_environments.environments[1]
2247
+ wallet_1_node: WalletNode = env.node
2248
+ wallet_1_rpc: WalletRpcClient = env.rpc_client
2249
+ wallet_2: Wallet = env_2.xch_wallet
2250
+ wallet_2_node: WalletNode = env_2.node
2251
+ wallet_2_rpc: WalletRpcClient = env_2.rpc_client
2252
+
2253
+ env.wallet_aliases = {
2254
+ "xch": 1,
2255
+ "nft": 2,
2256
+ }
2257
+ env_2.wallet_aliases = {
2258
+ "xch": 1,
2259
+ "nft": 2,
2260
+ }
2261
+
2262
+ create_wallet_res = await wallet_1_rpc.create_new_wallet(
2263
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, did_id=None, push=True),
2264
+ wallet_environments.tx_config,
2265
+ )
2266
+ nft_wallet_id = create_wallet_res.wallet_id
2267
+ await wallet_1_rpc.mint_nft(
2097
2268
  request=NFTMintNFTRequest(
2098
2269
  wallet_id=nft_wallet_id,
2099
2270
  royalty_address=None,
@@ -2102,14 +2273,24 @@ async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -
2102
2273
  uris=["https://www.chia.net/img/branding/chia-logo.svg"],
2103
2274
  push=True,
2104
2275
  ),
2105
- tx_config=DEFAULT_TX_CONFIG,
2276
+ tx_config=wallet_environments.tx_config,
2106
2277
  )
2107
2278
 
2108
- spend_bundle = mint_res.spend_bundle
2109
-
2110
- await farm_transaction(full_node_api, wallet_1_node, spend_bundle)
2111
-
2112
- await full_node_api.wait_for_wallet_synced(wallet_node=wallet_1_node, timeout=15)
2279
+ await wallet_environments.process_pending_states(
2280
+ [
2281
+ WalletStateTransition(
2282
+ pre_block_balance_updates={
2283
+ "xch": {"set_remainder": True},
2284
+ "nft": {"init": True, "set_remainder": True},
2285
+ },
2286
+ post_block_balance_updates={
2287
+ "xch": {"set_remainder": True},
2288
+ "nft": {"set_remainder": True},
2289
+ },
2290
+ ),
2291
+ WalletStateTransition(),
2292
+ ]
2293
+ )
2113
2294
 
2114
2295
  nft_wallet = wallet_1_node.wallet_state_manager.wallets[nft_wallet_id]
2115
2296
  assert isinstance(nft_wallet, NFTWallet)
@@ -2132,17 +2313,34 @@ async def test_nft_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -
2132
2313
  nft_info = (await wallet_1_rpc.get_nft_info(NFTGetInfo(hmr_nft_id))).nft_info
2133
2314
  assert nft_info.nft_coin_id == (await nft_wallet.get_current_nfts())[0].coin.name()
2134
2315
 
2135
- async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2316
+ async with wallet_2.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2136
2317
  addr = encode_puzzle_hash(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager), "txch")
2137
2318
  await wallet_1_rpc.transfer_nft(
2138
- NFTTransferNFT(wallet_id=nft_wallet_id, nft_coin_id=nft_id, target_address=addr, push=True), DEFAULT_TX_CONFIG
2319
+ NFTTransferNFT(wallet_id=nft_wallet_id, nft_coin_id=nft_id, target_address=addr, push=True),
2320
+ wallet_environments.tx_config,
2139
2321
  )
2140
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2141
- await farm_transaction_block(full_node_api, wallet_1_node)
2142
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 0)
2143
- await full_node_api.wait_for_wallet_synced(wallet_node=wallet_1_node, timeout=5)
2144
2322
 
2145
- await full_node_api.wait_for_wallet_synced(wallet_node=wallet_2_node, timeout=5)
2323
+ await wallet_environments.process_pending_states(
2324
+ [
2325
+ WalletStateTransition(
2326
+ pre_block_balance_updates={
2327
+ "xch": {"set_remainder": True},
2328
+ "nft": {"set_remainder": True},
2329
+ },
2330
+ post_block_balance_updates={
2331
+ "xch": {"set_remainder": True},
2332
+ "nft": {"set_remainder": True},
2333
+ },
2334
+ ),
2335
+ WalletStateTransition(
2336
+ pre_block_balance_updates={},
2337
+ post_block_balance_updates={
2338
+ "xch": {"set_remainder": True},
2339
+ "nft": {"init": True, "set_remainder": True},
2340
+ },
2341
+ ),
2342
+ ]
2343
+ )
2146
2344
 
2147
2345
  nft_wallet_id_1 = (
2148
2346
  await wallet_2_node.wallet_state_manager.get_all_wallet_info_entries(wallet_type=WalletType.NFT)
@@ -2261,13 +2459,19 @@ async def _check_delete_key(
2261
2459
  assert resp.used_for_pool_rewards is False
2262
2460
 
2263
2461
 
2462
+ @pytest.mark.parametrize(
2463
+ "wallet_environments",
2464
+ [{"num_environments": 1, "blocks_needed": [1]}],
2465
+ indirect=True,
2466
+ )
2467
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2264
2468
  @pytest.mark.anyio
2265
- async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2266
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2469
+ async def test_key_and_address_endpoints(wallet_environments: WalletTestFramework) -> None:
2470
+ env = wallet_environments.environments[0]
2267
2471
 
2268
- wallet: Wallet = env.wallet_1.wallet
2269
- wallet_node: WalletNode = env.wallet_1.node
2270
- client: WalletRpcClient = env.wallet_1.rpc_client
2472
+ wallet: Wallet = env.xch_wallet
2473
+ wallet_node: WalletNode = env.node
2474
+ client: WalletRpcClient = env.rpc_client
2271
2475
 
2272
2476
  address = (await client.get_next_address(GetNextAddress(uint32(1), True))).address
2273
2477
  assert len(address) > 10
@@ -2275,18 +2479,17 @@ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEn
2275
2479
  pks = (await client.get_public_keys()).pk_fingerprints
2276
2480
  assert len(pks) == 1
2277
2481
 
2278
- await generate_funds(env.full_node.api, env.wallet_1)
2279
-
2280
2482
  assert (await client.get_height_info()).height > 0
2281
2483
 
2282
- async with wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2484
+ async with wallet.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2283
2485
  ph = await action_scope.get_puzzle_hash(wallet.wallet_state_manager)
2486
+ await wallet_environments.full_node.wait_for_wallet_synced(wallet_node)
2284
2487
  addr = encode_puzzle_hash(ph, "txch")
2285
2488
  tx_amount = uint64(15600000)
2286
- await env.full_node.api.wait_for_wallet_synced(wallet_node=wallet_node, timeout=20)
2287
2489
  created_tx = (
2288
2490
  await client.send_transaction(
2289
- SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True), DEFAULT_TX_CONFIG
2491
+ SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True),
2492
+ wallet_environments.tx_config,
2290
2493
  )
2291
2494
  ).transaction
2292
2495
 
@@ -2340,7 +2543,9 @@ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEn
2340
2543
  assert delete_key_resp.used_for_farmer_rewards is False
2341
2544
  assert delete_key_resp.used_for_pool_rewards is False
2342
2545
 
2546
+ assert get_wallet_db_path(wallet_node.root_path, wallet_node.config, str(pks[0])).exists()
2343
2547
  await client.delete_key(DeleteKey(pks[0]))
2548
+ assert not get_wallet_db_path(wallet_node.root_path, wallet_node.config, str(pks[0])).exists()
2344
2549
  await client.log_in(LogIn(uint32(pks[1])))
2345
2550
  assert len((await client.get_public_keys()).pk_fingerprints) == 1
2346
2551
 
@@ -2353,28 +2558,46 @@ async def test_key_and_address_endpoints(wallet_rpc_environment: WalletRpcTestEn
2353
2558
  with pytest.raises(ValueError):
2354
2559
  await client.send_transaction(
2355
2560
  SendTransaction(wallet_id=uint32(wallets[0].id), amount=uint64(100), address=addr, push=True),
2356
- DEFAULT_TX_CONFIG,
2561
+ wallet_environments.tx_config,
2357
2562
  )
2358
2563
 
2359
2564
  # Delete all keys
2565
+ resp = await client.generate_mnemonic()
2566
+ add_key_resp = await client.add_key(AddKey(resp.mnemonic))
2567
+ assert get_wallet_db_path(wallet_node.root_path, wallet_node.config, str(pks[1])).exists()
2568
+ assert get_wallet_db_path(wallet_node.root_path, wallet_node.config, str(add_key_resp.fingerprint)).exists()
2360
2569
  await client.delete_all_keys()
2570
+ assert not get_wallet_db_path(wallet_node.root_path, wallet_node.config, str(pks[1])).exists()
2571
+ assert not get_wallet_db_path(wallet_node.root_path, wallet_node.config, str(add_key_resp.fingerprint)).exists()
2361
2572
  assert len((await client.get_public_keys()).pk_fingerprints) == 0
2362
2573
 
2363
2574
 
2575
+ @pytest.mark.parametrize(
2576
+ "wallet_environments",
2577
+ [{"num_environments": 2, "blocks_needed": [1, 0]}],
2578
+ indirect=True,
2579
+ )
2580
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2364
2581
  @pytest.mark.anyio
2365
- async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2366
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2582
+ async def test_select_coins_rpc(wallet_environments: WalletTestFramework) -> None:
2583
+ env = wallet_environments.environments[0]
2584
+ env_2 = wallet_environments.environments[1]
2367
2585
 
2368
- wallet_2: Wallet = env.wallet_2.wallet
2369
- wallet_node: WalletNode = env.wallet_1.node
2370
- full_node_api: FullNodeSimulator = env.full_node.api
2371
- client: WalletRpcClient = env.wallet_1.rpc_client
2372
- client_2: WalletRpcClient = env.wallet_2.rpc_client
2586
+ env.wallet_aliases = {"xch": 1}
2587
+ env_2.wallet_aliases = {"xch": 1}
2373
2588
 
2374
- funds = await generate_funds(full_node_api, env.wallet_1)
2589
+ wallet_2: Wallet = env_2.xch_wallet
2590
+ client: WalletRpcClient = env.rpc_client
2591
+ client_2: WalletRpcClient = env_2.rpc_client
2375
2592
 
2376
- async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2377
- addr = encode_puzzle_hash(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager), "txch")
2593
+ funds: int = await env.xch_wallet.get_confirmed_balance()
2594
+
2595
+ # since this wallet farms no blocks, this first request will always make a new puzzle hash
2596
+ with wallet_environments.new_puzzle_hashes_allowed():
2597
+ async with wallet_2.wallet_state_manager.new_action_scope(
2598
+ wallet_environments.tx_config, push=True
2599
+ ) as action_scope:
2600
+ addr = encode_puzzle_hash(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager), "txch")
2378
2601
  coin_300: list[Coin]
2379
2602
  tx_amounts: list[uint64] = [uint64(1000), uint64(300), uint64(1000), uint64(1000), uint64(10000)]
2380
2603
  for tx_amount in tx_amounts:
@@ -2382,7 +2605,8 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2382
2605
  # create coins for tests
2383
2606
  tx = (
2384
2607
  await client.send_transaction(
2385
- SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True), DEFAULT_TX_CONFIG
2608
+ SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True),
2609
+ wallet_environments.tx_config,
2386
2610
  )
2387
2611
  ).transaction
2388
2612
  spend_bundle = tx.spend_bundle
@@ -2391,16 +2615,27 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2391
2615
  if coin.amount == uint64(300):
2392
2616
  coin_300 = [coin]
2393
2617
 
2394
- await time_out_assert(20, tx_in_mempool, True, client, tx.name)
2395
- await farm_transaction(full_node_api, wallet_node, spend_bundle)
2396
- await time_out_assert(20, get_confirmed_balance, funds, client, 1)
2618
+ await wallet_environments.process_pending_states(
2619
+ [
2620
+ WalletStateTransition(
2621
+ pre_block_balance_updates={"xch": {"set_remainder": True}},
2622
+ post_block_balance_updates={"xch": {"set_remainder": True}},
2623
+ ),
2624
+ WalletStateTransition(
2625
+ pre_block_balance_updates={},
2626
+ post_block_balance_updates={"xch": {"set_remainder": True}},
2627
+ ),
2628
+ ]
2629
+ )
2397
2630
 
2398
2631
  # test min coin amount
2399
2632
  min_coins_response = await client_2.select_coins(
2400
2633
  SelectCoins.from_coin_selection_config(
2401
2634
  amount=uint64(1000),
2402
2635
  wallet_id=uint32(1),
2403
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(min_coin_amount=uint64(1001)),
2636
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2637
+ min_coin_amount=uint64(1001)
2638
+ ),
2404
2639
  )
2405
2640
  )
2406
2641
  assert len(min_coins_response.coins) == 1
@@ -2411,7 +2646,7 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2411
2646
  SelectCoins.from_coin_selection_config(
2412
2647
  amount=uint64(2000),
2413
2648
  wallet_id=uint32(1),
2414
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2649
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2415
2650
  min_coin_amount=uint64(999), max_coin_amount=uint64(9999)
2416
2651
  ),
2417
2652
  )
@@ -2425,7 +2660,9 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2425
2660
  SelectCoins.from_coin_selection_config(
2426
2661
  amount=uint64(non_1000_amt),
2427
2662
  wallet_id=uint32(1),
2428
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_amounts=[uint64(1000)]),
2663
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2664
+ excluded_coin_amounts=[uint64(1000)]
2665
+ ),
2429
2666
  )
2430
2667
  )
2431
2668
  assert len(excluded_amt_coins_response.coins) == len([a for a in tx_amounts if a != 1000])
@@ -2437,7 +2674,7 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2437
2674
  SelectCoins.from_coin_selection_config(
2438
2675
  amount=uint64(5000),
2439
2676
  wallet_id=uint32(1),
2440
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2677
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2441
2678
  excluded_coin_ids=[c.name() for c in min_coins_response.coins]
2442
2679
  ),
2443
2680
  )
@@ -2446,7 +2683,7 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2446
2683
  SelectCoins.from_coin_selection_config(
2447
2684
  amount=uint64(1300),
2448
2685
  wallet_id=uint32(1),
2449
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2686
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2450
2687
  excluded_coin_ids=[c.name() for c in coin_300]
2451
2688
  ),
2452
2689
  )
@@ -2474,7 +2711,7 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2474
2711
  spendable_coins_response = await client_2.get_spendable_coins(
2475
2712
  GetSpendableCoins.from_coin_selection_config(
2476
2713
  wallet_id=uint32(1),
2477
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(
2714
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2478
2715
  excluded_coin_ids=[c.name() for c in excluded_amt_coins_response.coins]
2479
2716
  ),
2480
2717
  ),
@@ -2488,14 +2725,18 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2488
2725
  spendable_coins_response = await client_2.get_spendable_coins(
2489
2726
  GetSpendableCoins.from_coin_selection_config(
2490
2727
  wallet_id=uint32(1),
2491
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_amounts=[uint64(1000)]),
2728
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2729
+ excluded_coin_amounts=[uint64(1000)]
2730
+ ),
2492
2731
  )
2493
2732
  )
2494
2733
  assert len([rec for rec in spendable_coins_response.confirmed_records if rec.coin.amount == 1000]) == 0
2495
2734
  spendable_coins_response = await client_2.get_spendable_coins(
2496
2735
  GetSpendableCoins.from_coin_selection_config(
2497
2736
  wallet_id=uint32(1),
2498
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(max_coin_amount=uint64(999)),
2737
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2738
+ max_coin_amount=uint64(999)
2739
+ ),
2499
2740
  )
2500
2741
  )
2501
2742
  assert spendable_coins_response.confirmed_records[0].coin == coin_300[0]
@@ -2503,16 +2744,24 @@ async def test_select_coins_rpc(wallet_rpc_environment: WalletRpcTestEnvironment
2503
2744
  await client_2.get_spendable_coins(
2504
2745
  GetSpendableCoins.from_coin_selection_config(
2505
2746
  wallet_id=uint32(1),
2506
- coin_selection_config=DEFAULT_COIN_SELECTION_CONFIG.override(excluded_coin_ids=[b"a"]),
2747
+ coin_selection_config=wallet_environments.tx_config.coin_selection_config.override(
2748
+ excluded_coin_ids=[b"a"]
2749
+ ),
2507
2750
  )
2508
2751
  )
2509
2752
 
2510
2753
 
2754
+ @pytest.mark.parametrize(
2755
+ "wallet_environments",
2756
+ [{"num_environments": 1, "blocks_needed": [0], "reuse_puzhash": True, "trusted": True}],
2757
+ indirect=True,
2758
+ )
2759
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2511
2760
  @pytest.mark.anyio
2512
- async def test_get_coin_records_rpc(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2513
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2514
- wallet_node: WalletNode = env.wallet_1.node
2515
- client: WalletRpcClient = env.wallet_1.rpc_client
2761
+ async def test_get_coin_records_rpc(wallet_environments: WalletTestFramework) -> None:
2762
+ env = wallet_environments.environments[0]
2763
+ wallet_node: WalletNode = env.node
2764
+ client: WalletRpcClient = env.rpc_client
2516
2765
  store = wallet_node.wallet_state_manager.coin_store
2517
2766
 
2518
2767
  for record in [record_1, record_2, record_3, record_4, record_5, record_6, record_7, record_8, record_9]:
@@ -2521,7 +2770,7 @@ async def test_get_coin_records_rpc(wallet_rpc_environment: WalletRpcTestEnviron
2521
2770
  async def run_test_case(
2522
2771
  test_case: str,
2523
2772
  test_request: GetCoinRecords,
2524
- test_total_count: Optional[int],
2773
+ test_total_count: int | None,
2525
2774
  test_records: list[WalletCoinRecord],
2526
2775
  ) -> None:
2527
2776
  response = await client.get_coin_records(test_request)
@@ -2554,28 +2803,28 @@ async def test_get_coin_records_rpc(wallet_rpc_environment: WalletRpcTestEnviron
2554
2803
  await run_test_case(f"{name}-{i}", request, expected_total_count, expected_records)
2555
2804
 
2556
2805
 
2806
+ @pytest.mark.parametrize(
2807
+ "wallet_environments",
2808
+ [{"num_environments": 1, "blocks_needed": [0], "reuse_puzhash": True, "trusted": True}],
2809
+ indirect=True,
2810
+ )
2811
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2557
2812
  @pytest.mark.anyio
2558
- async def test_get_coin_records_rpc_limits(
2559
- wallet_rpc_environment: WalletRpcTestEnvironment,
2560
- seeded_random: random.Random,
2561
- ) -> None:
2562
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2563
- wallet_node: WalletNode = env.wallet_1.node
2564
- client: WalletRpcClient = env.wallet_1.rpc_client
2565
- rpc_server = wallet_rpc_environment.wallet_1.service.rpc_server
2566
- assert rpc_server is not None
2567
- api: WalletRpcApi = rpc_server.rpc_api
2813
+ async def test_get_coin_records_rpc_limits(wallet_environments: WalletTestFramework) -> None:
2814
+ env = wallet_environments.environments[0]
2815
+ wallet_node: WalletNode = env.node
2816
+ client: WalletRpcClient = env.rpc_client
2568
2817
  store = wallet_node.wallet_state_manager.coin_store
2569
2818
 
2570
2819
  # Adjust the limits for faster testing
2571
2820
  WalletRpcApi.max_get_coin_records_limit = uint32(5)
2572
2821
  WalletRpcApi.max_get_coin_records_filter_items = uint32(5)
2573
2822
 
2574
- max_coins = api.max_get_coin_records_limit * 10
2823
+ max_coins = WalletRpcApi.max_get_coin_records_limit * 10
2575
2824
  coin_records = [
2576
2825
  WalletCoinRecord(
2577
- Coin(bytes32.random(seeded_random), bytes32.random(seeded_random), uint64(seeded_random.randrange(2**64))),
2578
- uint32(seeded_random.randrange(2**32)),
2826
+ Coin(bytes32(bytes([i] * 32)), bytes32(bytes([i] * 32)), uint64(i)),
2827
+ uint32(i),
2579
2828
  uint32(0),
2580
2829
  False,
2581
2830
  False,
@@ -2584,15 +2833,15 @@ async def test_get_coin_records_rpc_limits(
2584
2833
  CoinType.NORMAL,
2585
2834
  None,
2586
2835
  )
2587
- for _ in range(max_coins)
2836
+ for i in range(max_coins)
2588
2837
  ]
2589
2838
  for record in coin_records:
2590
2839
  await store.add_coin_record(record)
2591
2840
 
2592
- limit = api.max_get_coin_records_limit
2841
+ limit = WalletRpcApi.max_get_coin_records_limit
2593
2842
  response_records = []
2594
- for i in range(int(max_coins / api.max_get_coin_records_limit)):
2595
- offset = uint32(api.max_get_coin_records_limit * i)
2843
+ for i in range(int(max_coins / WalletRpcApi.max_get_coin_records_limit)):
2844
+ offset = uint32(WalletRpcApi.max_get_coin_records_limit * i)
2596
2845
  response = await client.get_coin_records(GetCoinRecords(limit=limit, offset=offset, include_total_count=True))
2597
2846
  response_records.extend(list(response["coin_records"]))
2598
2847
 
@@ -2603,7 +2852,7 @@ async def test_get_coin_records_rpc_limits(
2603
2852
  assert expected_record in response_records
2604
2853
 
2605
2854
  # Request coins with the max number of filter items
2606
- max_filter_items = api.max_get_coin_records_filter_items
2855
+ max_filter_items = WalletRpcApi.max_get_coin_records_filter_items
2607
2856
  filter_records = coin_records[:max_filter_items]
2608
2857
  coin_id_filter = HashFilter.include([coin.name() for coin in filter_records])
2609
2858
  puzzle_hash_filter = HashFilter.include([coin.coin.puzzle_hash for coin in filter_records])
@@ -2627,24 +2876,22 @@ async def test_get_coin_records_rpc_limits(
2627
2876
  assert expected_record in response["coin_records"]
2628
2877
 
2629
2878
 
2879
+ @pytest.mark.parametrize(
2880
+ "wallet_environments",
2881
+ [{"num_environments": 1, "blocks_needed": [0], "reuse_puzhash": True, "trusted": True}],
2882
+ indirect=True,
2883
+ )
2884
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2630
2885
  @pytest.mark.anyio
2631
- async def test_get_coin_records_rpc_failures(
2632
- wallet_rpc_environment: WalletRpcTestEnvironment,
2633
- seeded_random: random.Random,
2634
- ) -> None:
2635
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2636
- client: WalletRpcClient = env.wallet_1.rpc_client
2637
- rpc_server = wallet_rpc_environment.wallet_1.service.rpc_server
2638
- assert rpc_server is not None
2639
- api = rpc_server.rpc_api
2640
-
2641
- too_many_hashes = [bytes32.random(seeded_random) for _ in range(api.max_get_coin_records_filter_items + 1)]
2642
- too_many_amounts = [
2643
- uint64(uint64(seeded_random.randrange(2**64))) for _ in range(api.max_get_coin_records_filter_items + 1)
2644
- ]
2886
+ async def test_get_coin_records_rpc_failures(wallet_environments: WalletTestFramework) -> None:
2887
+ env = wallet_environments.environments[0]
2888
+ client: WalletRpcClient = env.rpc_client
2889
+
2890
+ too_many_hashes = [bytes32.secret() for i in range(WalletRpcApi.max_get_coin_records_filter_items + 1)]
2891
+ too_many_amounts = [uint64(i) for i in range(WalletRpcApi.max_get_coin_records_filter_items + 1)]
2645
2892
  # Run requests which exceeds the allowed limit and contain too much filter items
2646
2893
  for name, request in {
2647
- "limit": GetCoinRecords(limit=uint32(api.max_get_coin_records_limit + 1)),
2894
+ "limit": GetCoinRecords(limit=uint32(WalletRpcApi.max_get_coin_records_limit + 1)),
2648
2895
  "coin_id_filter": GetCoinRecords(coin_id_filter=HashFilter.include(too_many_hashes)),
2649
2896
  "puzzle_hash_filter": GetCoinRecords(puzzle_hash_filter=HashFilter.include(too_many_hashes)),
2650
2897
  "parent_coin_id_filter": GetCoinRecords(parent_coin_id_filter=HashFilter.include(too_many_hashes)),
@@ -2653,44 +2900,33 @@ async def test_get_coin_records_rpc_failures(
2653
2900
  with pytest.raises(ValueError, match=name):
2654
2901
  await client.get_coin_records(request)
2655
2902
 
2656
- # Type validation is handled via `Streamable.from_json_dict` but the below should make at least sure it triggers.
2657
- for field, value in {
2658
- "offset": "invalid",
2659
- "limit": "invalid",
2660
- "wallet_id": "invalid",
2661
- "wallet_type": 100,
2662
- "coin_type": 100,
2663
- "coin_id_filter": "invalid",
2664
- "puzzle_hash_filter": "invalid",
2665
- "parent_coin_id_filter": "invalid",
2666
- "amount_filter": "invalid",
2667
- "amount_range": "invalid",
2668
- "confirmed_range": "invalid",
2669
- "spent_range": "invalid",
2670
- "order": 8,
2671
- }.items():
2672
- with pytest.raises((ConversionError, InvalidTypeError, ValueError)):
2673
- json_dict = GetCoinRecords().to_json_dict()
2674
- json_dict[field] = value
2675
- await api.get_coin_records(json_dict)
2676
-
2677
2903
 
2904
+ @pytest.mark.parametrize(
2905
+ "wallet_environments",
2906
+ [
2907
+ {
2908
+ "num_environments": 2,
2909
+ "blocks_needed": [1, 1],
2910
+ "config_overrides": {"enable_notifications": True, "required_notification_amount": 100000000000},
2911
+ }
2912
+ ],
2913
+ indirect=True,
2914
+ )
2915
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
2678
2916
  @pytest.mark.anyio
2679
- async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2680
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2681
-
2682
- wallet_2: Wallet = env.wallet_2.wallet
2683
- wallet_node: WalletNode = env.wallet_1.node
2684
- full_node_api: FullNodeSimulator = env.full_node.api
2685
- client: WalletRpcClient = env.wallet_1.rpc_client
2686
- client_2: WalletRpcClient = env.wallet_2.rpc_client
2917
+ async def test_notification_rpcs(wallet_environments: WalletTestFramework) -> None:
2918
+ env = wallet_environments.environments[0]
2919
+ env_2 = wallet_environments.environments[1]
2687
2920
 
2688
- await generate_funds(full_node_api, env.wallet_1)
2921
+ env.wallet_aliases = {"xch": 1}
2922
+ env_2.wallet_aliases = {"xch": 1}
2689
2923
 
2690
- env.wallet_2.node.config["enable_notifications"] = True
2691
- env.wallet_2.node.config["required_notification_amount"] = 100000000000
2692
- async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2693
- response = await client.send_notification(
2924
+ wallet_2: Wallet = env_2.xch_wallet
2925
+ client: WalletRpcClient = env.rpc_client
2926
+ client_2: WalletRpcClient = env_2.rpc_client
2927
+
2928
+ async with wallet_2.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2929
+ await client.send_notification(
2694
2930
  SendNotification(
2695
2931
  target=(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)),
2696
2932
  message=b"hello",
@@ -2698,18 +2934,29 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
2698
2934
  fee=uint64(100000000000),
2699
2935
  push=True,
2700
2936
  ),
2701
- tx_config=DEFAULT_TX_CONFIG,
2937
+ tx_config=wallet_environments.tx_config,
2702
2938
  )
2703
2939
 
2704
- assert response.tx.spend_bundle is not None
2705
- await time_out_assert(
2706
- 5,
2707
- full_node_api.full_node.mempool_manager.get_spendbundle,
2708
- response.tx.spend_bundle,
2709
- response.tx.spend_bundle.name(),
2940
+ await wallet_environments.process_pending_states(
2941
+ [
2942
+ WalletStateTransition(
2943
+ pre_block_balance_updates={
2944
+ "xch": {"set_remainder": True},
2945
+ },
2946
+ post_block_balance_updates={
2947
+ "xch": {"set_remainder": True},
2948
+ },
2949
+ ),
2950
+ WalletStateTransition(
2951
+ pre_block_balance_updates={
2952
+ "xch": {"set_remainder": True},
2953
+ },
2954
+ post_block_balance_updates={
2955
+ "xch": {"set_remainder": True},
2956
+ },
2957
+ ),
2958
+ ]
2710
2959
  )
2711
- await farm_transaction(full_node_api, wallet_node, response.tx.spend_bundle)
2712
- await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(100000000000))
2713
2960
 
2714
2961
  notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
2715
2962
  assert [notification] == (await client_2.get_notifications(GetNotifications([notification.id]))).notifications
@@ -2720,8 +2967,8 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
2720
2967
  await client_2.delete_notifications(DeleteNotifications())
2721
2968
  assert [] == (await client_2.get_notifications(GetNotifications([notification.id]))).notifications
2722
2969
 
2723
- async with wallet_2.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
2724
- response = await client.send_notification(
2970
+ async with wallet_2.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2971
+ await client.send_notification(
2725
2972
  SendNotification(
2726
2973
  target=(await action_scope.get_puzzle_hash(wallet_2.wallet_state_manager)),
2727
2974
  message=b"hello",
@@ -2729,18 +2976,29 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
2729
2976
  fee=uint64(100000000000),
2730
2977
  push=True,
2731
2978
  ),
2732
- tx_config=DEFAULT_TX_CONFIG,
2979
+ tx_config=wallet_environments.tx_config,
2733
2980
  )
2734
2981
 
2735
- assert response.tx.spend_bundle is not None
2736
- await time_out_assert(
2737
- 5,
2738
- full_node_api.full_node.mempool_manager.get_spendbundle,
2739
- response.tx.spend_bundle,
2740
- response.tx.spend_bundle.name(),
2982
+ await wallet_environments.process_pending_states(
2983
+ [
2984
+ WalletStateTransition(
2985
+ pre_block_balance_updates={
2986
+ "xch": {"set_remainder": True},
2987
+ },
2988
+ post_block_balance_updates={
2989
+ "xch": {"set_remainder": True},
2990
+ },
2991
+ ),
2992
+ WalletStateTransition(
2993
+ pre_block_balance_updates={
2994
+ "xch": {"set_remainder": True},
2995
+ },
2996
+ post_block_balance_updates={
2997
+ "xch": {"set_remainder": True},
2998
+ },
2999
+ ),
3000
+ ]
2741
3001
  )
2742
- await farm_transaction(full_node_api, wallet_node, response.tx.spend_bundle)
2743
- await time_out_assert(20, env.wallet_2.wallet.get_confirmed_balance, uint64(200000000000))
2744
3002
 
2745
3003
  notification = (await client_2.get_notifications(GetNotifications())).notifications[0]
2746
3004
  await client_2.delete_notifications(DeleteNotifications([notification.id]))
@@ -2882,82 +3140,120 @@ async def test_notification_rpcs(wallet_rpc_environment: WalletRpcTestEnvironmen
2882
3140
  ],
2883
3141
  )
2884
3142
  @pytest.mark.parametrize("prefix_hex_strings", [True, False], ids=["with 0x", "no 0x"])
3143
+ @pytest.mark.parametrize(
3144
+ "wallet_environments",
3145
+ [
3146
+ {
3147
+ "num_environments": 1,
3148
+ "blocks_needed": [1],
3149
+ "reuse_puzhash": True,
3150
+ "trusted": True,
3151
+ }
3152
+ ],
3153
+ indirect=True,
3154
+ )
2885
3155
  @pytest.mark.anyio
2886
3156
  @pytest.mark.limit_consensus_modes(reason="irrelevant")
2887
3157
  async def test_verify_signature(
2888
- wallet_rpc_environment: WalletRpcTestEnvironment,
3158
+ wallet_environments: WalletTestFramework,
2889
3159
  rpc_request: dict[str, Any],
2890
3160
  rpc_response: VerifySignatureResponse,
2891
3161
  prefix_hex_strings: bool,
2892
3162
  ) -> None:
2893
- rpc_server = wallet_rpc_environment.wallet_1.service.rpc_server
2894
- assert rpc_server is not None
2895
3163
  updated_request = rpc_request.copy()
2896
3164
  updated_request["pubkey"] = ("0x" if prefix_hex_strings else "") + updated_request["pubkey"]
2897
3165
  updated_request["signature"] = ("0x" if prefix_hex_strings else "") + updated_request["signature"]
2898
- res = await wallet_rpc_environment.wallet_1.rpc_client.verify_signature(
3166
+ res = await wallet_environments.environments[0].rpc_client.verify_signature(
2899
3167
  VerifySignature.from_json_dict(updated_request)
2900
3168
  )
2901
3169
  assert res == rpc_response
2902
3170
 
2903
3171
 
3172
+ @pytest.mark.parametrize(
3173
+ "wallet_environments",
3174
+ [
3175
+ {
3176
+ "num_environments": 1,
3177
+ "blocks_needed": [1],
3178
+ "reuse_puzhash": True,
3179
+ "trusted": True,
3180
+ }
3181
+ ],
3182
+ indirect=True,
3183
+ )
2904
3184
  @pytest.mark.anyio
2905
3185
  @pytest.mark.limit_consensus_modes(reason="irrelevant")
2906
- async def test_set_auto_claim(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2907
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2908
- full_node_api: FullNodeSimulator = env.full_node.api
2909
- rpc_server = wallet_rpc_environment.wallet_1.service.rpc_server
2910
- await generate_funds(full_node_api, env.wallet_1)
2911
- assert rpc_server is not None
2912
- api: WalletRpcApi = rpc_server.rpc_api
2913
- req = {"enabled": False, "tx_fee": -1, "min_amount": 100}
2914
- has_exception = False
2915
- try:
2916
- # Manually using API to test error condition
2917
- await api.set_auto_claim(req)
2918
- except ConversionError:
2919
- has_exception = True
2920
- assert has_exception
2921
- req = {"enabled": False, "batch_size": 0, "min_amount": 100}
2922
- res = await env.wallet_1.rpc_client.set_auto_claim(
2923
- AutoClaimSettings(enabled=False, batch_size=uint16(0), min_amount=uint64(100))
3186
+ async def test_sign_message_by_address(wallet_environments: WalletTestFramework) -> None:
3187
+ client: WalletRpcClient = wallet_environments.environments[0].rpc_client
3188
+
3189
+ message = "foo"
3190
+ address = await client.get_next_address(GetNextAddress(uint32(1)))
3191
+ signed_message = await client.sign_message_by_address(SignMessageByAddress(address.address, message))
3192
+
3193
+ await wallet_environments.environments[0].rpc_client.verify_signature(
3194
+ VerifySignature(
3195
+ message=message,
3196
+ pubkey=signed_message.pubkey,
3197
+ signature=signed_message.signature,
3198
+ signing_mode=signed_message.signing_mode,
3199
+ )
2924
3200
  )
2925
- assert not res.enabled
2926
- assert res.tx_fee == 0
2927
- assert res.min_amount == 100
2928
- assert res.batch_size == 50
2929
3201
 
2930
3202
 
2931
- @pytest.mark.anyio
3203
+ @pytest.mark.parametrize(
3204
+ "wallet_environments",
3205
+ [{"num_environments": 2, "blocks_needed": [1, 0]}],
3206
+ indirect=True,
3207
+ )
2932
3208
  @pytest.mark.limit_consensus_modes(reason="irrelevant")
2933
- async def test_get_auto_claim(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2934
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2935
- full_node_api: FullNodeSimulator = env.full_node.api
2936
- rpc_server = wallet_rpc_environment.wallet_1.service.rpc_server
2937
- await generate_funds(full_node_api, env.wallet_1)
2938
- assert rpc_server is not None
2939
- res = await env.wallet_1.rpc_client.get_auto_claim()
2940
- assert not res.enabled
2941
- assert res.tx_fee == 0
2942
- assert res.min_amount == 0
2943
- assert res.batch_size == 50
3209
+ @pytest.mark.anyio
3210
+ async def test_set_wallet_resync_on_startup(wallet_environments: WalletTestFramework) -> None:
3211
+ env = wallet_environments.environments[0]
3212
+ env_2 = wallet_environments.environments[1]
3213
+ client: WalletRpcClient = env.rpc_client
3214
+ wc = env.rpc_client
2944
3215
 
3216
+ env.wallet_aliases = {
3217
+ "xch": 1,
3218
+ "did": 2,
3219
+ "nft1": 3,
3220
+ "nft0": 4,
3221
+ }
2945
3222
 
2946
- @pytest.mark.anyio
2947
- async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
2948
- env: WalletRpcTestEnvironment = wallet_rpc_environment
2949
- full_node_api: FullNodeSimulator = env.full_node.api
2950
- client: WalletRpcClient = env.wallet_1.rpc_client
2951
- await generate_funds(full_node_api, env.wallet_1)
2952
- wc = env.wallet_1.rpc_client
2953
- await wc.create_new_did_wallet(1, DEFAULT_TX_CONFIG, 0)
2954
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2955
- await farm_transaction_block(full_node_api, env.wallet_1.node)
2956
- await time_out_assert(20, check_client_synced, True, wc)
2957
-
2958
- nft_wallet = await wc.create_new_nft_wallet(None)
2959
- nft_wallet_id = nft_wallet["wallet_id"]
2960
- address = (await wc.get_next_address(GetNextAddress(env.wallet_1.wallet.id(), True))).address
3223
+ await wc.create_new_wallet(
3224
+ CreateNewWallet(
3225
+ wallet_type=CreateNewWalletType.DID_WALLET,
3226
+ did_type=DIDType.NEW,
3227
+ amount=uint64(1),
3228
+ push=True,
3229
+ ),
3230
+ tx_config=wallet_environments.tx_config,
3231
+ )
3232
+
3233
+ await wallet_environments.process_pending_states(
3234
+ [
3235
+ WalletStateTransition(
3236
+ pre_block_balance_updates={
3237
+ "xch": {"set_remainder": True},
3238
+ "did": {"init": True, "set_remainder": True},
3239
+ "nft1": {"init": True, "set_remainder": True},
3240
+ },
3241
+ post_block_balance_updates={
3242
+ "xch": {"set_remainder": True},
3243
+ "did": {"set_remainder": True},
3244
+ "nft1": {"set_remainder": True},
3245
+ },
3246
+ ),
3247
+ WalletStateTransition(),
3248
+ ]
3249
+ )
3250
+
3251
+ nft_wallet_res = await wc.create_new_wallet(
3252
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, did_id=None, push=True),
3253
+ wallet_environments.tx_config,
3254
+ )
3255
+ nft_wallet_id = nft_wallet_res.wallet_id
3256
+ address = (await wc.get_next_address(GetNextAddress(env.xch_wallet.id(), True))).address
2961
3257
  await wc.mint_nft(
2962
3258
  request=NFTMintNFTRequest(
2963
3259
  wallet_id=nft_wallet_id,
@@ -2967,14 +3263,31 @@ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTes
2967
3263
  uris=["http://test.nft"],
2968
3264
  push=True,
2969
3265
  ),
2970
- tx_config=DEFAULT_TX_CONFIG,
3266
+ tx_config=wallet_environments.tx_config,
2971
3267
  )
2972
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 1)
2973
- await farm_transaction_block(full_node_api, env.wallet_1.node)
2974
- await time_out_assert(20, check_client_synced, True, wc)
2975
3268
 
2976
- wallet_node: WalletNode = env.wallet_1.node
2977
- wallet_node_2: WalletNode = env.wallet_2.node
3269
+ await wallet_environments.process_pending_states(
3270
+ [
3271
+ WalletStateTransition(
3272
+ pre_block_balance_updates={
3273
+ "xch": {"set_remainder": True},
3274
+ "did": {"set_remainder": True},
3275
+ "nft1": {"set_remainder": True},
3276
+ "nft0": {"init": True, "set_remainder": True},
3277
+ },
3278
+ post_block_balance_updates={
3279
+ "xch": {"set_remainder": True},
3280
+ "did": {"set_remainder": True},
3281
+ "nft1": {"set_remainder": True},
3282
+ "nft0": {"set_remainder": True},
3283
+ },
3284
+ ),
3285
+ WalletStateTransition(),
3286
+ ]
3287
+ )
3288
+
3289
+ wallet_node: WalletNode = env.node
3290
+ wallet_node_2: WalletNode = env_2.node
2978
3291
  # Test Clawback resync
2979
3292
  tx = (
2980
3293
  await wc.send_transaction(
@@ -2985,21 +3298,57 @@ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTes
2985
3298
  puzzle_decorator=[ClawbackPuzzleDecoratorOverride(decorator="CLAWBACK", clawback_timelock=uint64(5))],
2986
3299
  push=True,
2987
3300
  ),
2988
- tx_config=DEFAULT_TX_CONFIG,
3301
+ tx_config=wallet_environments.tx_config,
2989
3302
  )
2990
3303
  ).transaction
2991
3304
  clawback_coin_id = tx.additions[0].name()
2992
- assert tx.spend_bundle is not None
2993
- await farm_transaction(full_node_api, wallet_node, tx.spend_bundle)
2994
- await time_out_assert(20, check_client_synced, True, wc)
2995
- await asyncio.sleep(10)
3305
+
3306
+ await wallet_environments.process_pending_states(
3307
+ [
3308
+ WalletStateTransition(
3309
+ pre_block_balance_updates={
3310
+ "xch": {"set_remainder": True},
3311
+ "did": {"set_remainder": True},
3312
+ "nft1": {"set_remainder": True},
3313
+ "nft0": {"set_remainder": True},
3314
+ },
3315
+ post_block_balance_updates={
3316
+ "xch": {"set_remainder": True},
3317
+ "did": {"set_remainder": True},
3318
+ "nft1": {"set_remainder": True},
3319
+ "nft0": {"set_remainder": True},
3320
+ },
3321
+ ),
3322
+ WalletStateTransition(),
3323
+ ]
3324
+ )
3325
+
2996
3326
  resp = await wc.spend_clawback_coins(
2997
- SpendClawbackCoins(coin_ids=[clawback_coin_id], fee=uint64(0), push=True), tx_config=DEFAULT_TX_CONFIG
3327
+ SpendClawbackCoins(coin_ids=[clawback_coin_id], fee=uint64(0), push=True),
3328
+ tx_config=wallet_environments.tx_config,
2998
3329
  )
2999
3330
  assert len(resp.transaction_ids) == 1
3000
- await time_out_assert_not_none(10, full_node_api.full_node.mempool_manager.get_spendbundle, resp.transaction_ids[0])
3001
- await farm_transaction_block(full_node_api, wallet_node)
3002
- await time_out_assert(20, check_client_synced, True, wc)
3331
+
3332
+ await wallet_environments.process_pending_states(
3333
+ [
3334
+ WalletStateTransition(
3335
+ pre_block_balance_updates={
3336
+ "xch": {"set_remainder": True},
3337
+ "did": {"set_remainder": True},
3338
+ "nft1": {"set_remainder": True},
3339
+ "nft0": {"set_remainder": True},
3340
+ },
3341
+ post_block_balance_updates={
3342
+ "xch": {"set_remainder": True},
3343
+ "did": {"set_remainder": True},
3344
+ "nft1": {"set_remainder": True},
3345
+ "nft0": {"set_remainder": True},
3346
+ },
3347
+ ),
3348
+ WalletStateTransition(),
3349
+ ]
3350
+ )
3351
+
3003
3352
  wallet_node_2._close()
3004
3353
  await wallet_node_2._await_closed()
3005
3354
  # set flag to reset wallet sync data on start
@@ -3044,14 +3393,19 @@ async def test_set_wallet_resync_on_startup(wallet_rpc_environment: WalletRpcTes
3044
3393
  await wallet_node_2._await_closed()
3045
3394
 
3046
3395
 
3396
+ @pytest.mark.parametrize(
3397
+ "wallet_environments",
3398
+ [{"num_environments": 2, "blocks_needed": [1, 0]}],
3399
+ indirect=True,
3400
+ )
3401
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
3047
3402
  @pytest.mark.anyio
3048
- async def test_set_wallet_resync_on_startup_disable(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
3049
- env: WalletRpcTestEnvironment = wallet_rpc_environment
3050
- full_node_api: FullNodeSimulator = env.full_node.api
3051
- client: WalletRpcClient = env.wallet_1.rpc_client
3052
- await generate_funds(full_node_api, env.wallet_1)
3053
- wallet_node: WalletNode = env.wallet_1.node
3054
- wallet_node_2: WalletNode = env.wallet_2.node
3403
+ async def test_set_wallet_resync_on_startup_disable(wallet_environments: WalletTestFramework) -> None:
3404
+ env = wallet_environments.environments[0]
3405
+ env_2 = wallet_environments.environments[1]
3406
+ client: WalletRpcClient = env.rpc_client
3407
+ wallet_node: WalletNode = env.node
3408
+ wallet_node_2: WalletNode = env_2.node
3055
3409
  wallet_node_2._close()
3056
3410
  await wallet_node_2._await_closed()
3057
3411
  # set flag to reset wallet sync data on start
@@ -3083,13 +3437,16 @@ async def test_set_wallet_resync_on_startup_disable(wallet_rpc_environment: Wall
3083
3437
  await wallet_node_2._await_closed()
3084
3438
 
3085
3439
 
3086
- @pytest.mark.anyio
3440
+ @pytest.mark.parametrize(
3441
+ "wallet_environments",
3442
+ [{"num_environments": 1, "blocks_needed": [0]}],
3443
+ indirect=True,
3444
+ )
3087
3445
  @pytest.mark.limit_consensus_modes(reason="irrelevant")
3088
- async def test_set_wallet_resync_schema(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
3089
- env: WalletRpcTestEnvironment = wallet_rpc_environment
3090
- full_node_api: FullNodeSimulator = env.full_node.api
3091
- await generate_funds(full_node_api, env.wallet_1)
3092
- wallet_node: WalletNode = env.wallet_1.node
3446
+ @pytest.mark.anyio
3447
+ async def test_set_wallet_resync_schema(wallet_environments: WalletTestFramework) -> None:
3448
+ env = wallet_environments.environments[0]
3449
+ wallet_node: WalletNode = env.node
3093
3450
  fingerprint = wallet_node.logged_in_fingerprint
3094
3451
  assert fingerprint is not None
3095
3452
  db_path = wallet_node.wallet_state_manager.db_path
@@ -3106,21 +3463,30 @@ async def test_set_wallet_resync_schema(wallet_rpc_environment: WalletRpcTestEnv
3106
3463
  )
3107
3464
 
3108
3465
 
3466
+ @pytest.mark.parametrize(
3467
+ "wallet_environments",
3468
+ [{"num_environments": 1, "blocks_needed": [1]}],
3469
+ indirect=True,
3470
+ )
3471
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
3109
3472
  @pytest.mark.anyio
3110
- async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
3111
- env: WalletRpcTestEnvironment = wallet_rpc_environment
3473
+ async def test_cat_spend_run_tail(wallet_environments: WalletTestFramework) -> None:
3474
+ env = wallet_environments.environments[0]
3112
3475
 
3113
- wallet_node: WalletNode = env.wallet_1.node
3114
- client: WalletRpcClient = env.wallet_1.rpc_client
3115
- full_node_api: FullNodeSimulator = env.full_node.api
3116
- full_node_rpc: FullNodeRpcClient = env.full_node.rpc_client
3476
+ wallet_node: WalletNode = env.node
3477
+ client: WalletRpcClient = env.rpc_client
3478
+ full_node_api: FullNodeSimulator = wallet_environments.full_node
3479
+ full_node_rpc: FullNodeRpcClient = wallet_environments.full_node_rpc_client
3117
3480
 
3118
- await generate_funds(full_node_api, env.wallet_1, 1)
3481
+ env.wallet_aliases = {
3482
+ "xch": 1,
3483
+ "cat": 2,
3484
+ }
3119
3485
 
3120
3486
  # Send to a CAT with an anyone can spend TAIL
3121
- async with env.wallet_1.wallet.wallet_state_manager.new_action_scope(DEFAULT_TX_CONFIG, push=True) as action_scope:
3122
- our_ph = await action_scope.get_puzzle_hash(env.wallet_1.wallet.wallet_state_manager)
3123
- cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, Program.to(None).get_tree_hash(), Program.to(1))
3487
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
3488
+ our_ph = await action_scope.get_puzzle_hash(env.wallet_state_manager)
3489
+ cat_puzzle: Program = construct_cat_puzzle(CAT_MOD, Program.NIL.get_tree_hash(), Program.to(1))
3124
3490
  addr = encode_puzzle_hash(
3125
3491
  cat_puzzle.get_tree_hash(),
3126
3492
  "txch",
@@ -3129,15 +3495,25 @@ async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironme
3129
3495
 
3130
3496
  tx = (
3131
3497
  await client.send_transaction(
3132
- SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True), DEFAULT_TX_CONFIG
3498
+ SendTransaction(wallet_id=uint32(1), amount=tx_amount, address=addr, push=True),
3499
+ wallet_environments.tx_config,
3133
3500
  )
3134
3501
  ).transaction
3135
- transaction_id = tx.name
3136
3502
  spend_bundle = tx.spend_bundle
3137
3503
  assert spend_bundle is not None
3138
3504
 
3139
- await time_out_assert(20, tx_in_mempool, True, client, transaction_id)
3140
- await farm_transaction(full_node_api, wallet_node, spend_bundle)
3505
+ await wallet_environments.process_pending_states(
3506
+ [
3507
+ WalletStateTransition(
3508
+ pre_block_balance_updates={
3509
+ "xch": {"set_remainder": True},
3510
+ },
3511
+ post_block_balance_updates={
3512
+ "xch": {"set_remainder": True},
3513
+ },
3514
+ )
3515
+ ]
3516
+ )
3141
3517
 
3142
3518
  # Do the eve spend back to our wallet
3143
3519
  cat_coin = next(c for c in spend_bundle.additions() if c.amount == tx_amount)
@@ -3165,10 +3541,26 @@ async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironme
3165
3541
  await farm_transaction(full_node_api, wallet_node, eve_spend)
3166
3542
 
3167
3543
  # Make sure we have the CAT
3168
- res = await client.create_wallet_for_existing_cat(Program.to(None).get_tree_hash())
3169
- assert res["success"]
3170
- cat_wallet_id = res["wallet_id"]
3171
- await time_out_assert(20, get_confirmed_balance, tx_amount, client, cat_wallet_id)
3544
+ create_wallet_res = await client.create_new_wallet(
3545
+ CreateNewWallet(
3546
+ wallet_type=CreateNewWalletType.CAT_WALLET,
3547
+ mode=WalletCreationMode.EXISTING,
3548
+ asset_id=Program.to(None).get_tree_hash(),
3549
+ push=True,
3550
+ ),
3551
+ tx_config=wallet_environments.tx_config,
3552
+ )
3553
+ cat_wallet_id = create_wallet_res.wallet_id
3554
+ await wallet_environments.process_pending_states(
3555
+ [
3556
+ WalletStateTransition(
3557
+ pre_block_balance_updates={
3558
+ "cat": {"init": True, "set_remainder": True},
3559
+ },
3560
+ post_block_balance_updates={},
3561
+ )
3562
+ ]
3563
+ )
3172
3564
 
3173
3565
  # Attempt to melt it fully
3174
3566
  tx = (
@@ -3182,40 +3574,89 @@ async def test_cat_spend_run_tail(wallet_rpc_environment: WalletRpcTestEnvironme
3182
3574
  tail_solution=b"\x80",
3183
3575
  push=True,
3184
3576
  ),
3185
- tx_config=DEFAULT_TX_CONFIG,
3577
+ tx_config=wallet_environments.tx_config,
3186
3578
  )
3187
3579
  ).transaction
3188
- transaction_id = tx.name
3189
- spend_bundle = tx.spend_bundle
3190
- assert spend_bundle is not None
3191
-
3192
- await time_out_assert(20, tx_in_mempool, True, client, transaction_id)
3193
- await farm_transaction(full_node_api, wallet_node, spend_bundle)
3194
3580
 
3195
- await time_out_assert(20, get_confirmed_balance, 0, client, cat_wallet_id)
3581
+ await wallet_environments.process_pending_states(
3582
+ [
3583
+ WalletStateTransition(
3584
+ pre_block_balance_updates={
3585
+ "xch": {},
3586
+ "cat": {
3587
+ "unconfirmed_wallet_balance": -tx_amount,
3588
+ "spendable_balance": -tx_amount,
3589
+ "max_send_amount": -tx_amount,
3590
+ "pending_coin_removal_count": 1,
3591
+ },
3592
+ },
3593
+ post_block_balance_updates={
3594
+ "xch": {},
3595
+ "cat": {
3596
+ "confirmed_wallet_balance": -tx_amount,
3597
+ "pending_coin_removal_count": -1,
3598
+ },
3599
+ },
3600
+ )
3601
+ ]
3602
+ )
3196
3603
 
3197
3604
 
3605
+ @pytest.mark.parametrize(
3606
+ "wallet_environments",
3607
+ [{"num_environments": 1, "blocks_needed": [1]}],
3608
+ indirect=True,
3609
+ )
3610
+ @pytest.mark.limit_consensus_modes(reason="irrelevant")
3198
3611
  @pytest.mark.anyio
3199
- async def test_get_balances(wallet_rpc_environment: WalletRpcTestEnvironment) -> None:
3200
- env: WalletRpcTestEnvironment = wallet_rpc_environment
3201
-
3202
- client: WalletRpcClient = env.wallet_1.rpc_client
3203
- wallet_node: WalletNode = env.wallet_1.node
3204
-
3205
- full_node_api: FullNodeSimulator = env.full_node.api
3612
+ async def test_get_balances(wallet_environments: WalletTestFramework) -> None:
3613
+ env = wallet_environments.environments[0]
3614
+ client: WalletRpcClient = env.rpc_client
3206
3615
 
3207
- await generate_funds(full_node_api, env.wallet_1, 1)
3616
+ env.wallet_aliases = {
3617
+ "xch": 1,
3618
+ "cat": 2,
3619
+ "cat2": 3,
3620
+ }
3208
3621
 
3209
- await time_out_assert(20, check_client_synced, True, client)
3210
3622
  # Creates a CAT wallet with 100 mojos and a CAT with 20 mojos
3211
- await client.create_new_cat_and_wallet(uint64(100), test=True)
3212
-
3213
- await time_out_assert(20, check_client_synced, True, client)
3214
- res = await client.create_new_cat_and_wallet(uint64(20), test=True)
3215
- assert res["success"]
3216
- await time_out_assert(5, check_mempool_spend_count, True, full_node_api, 2)
3217
- await farm_transaction_block(full_node_api, wallet_node)
3218
- await time_out_assert(20, check_client_synced, True, client)
3623
+ await client.create_new_wallet(
3624
+ CreateNewWallet(
3625
+ wallet_type=CreateNewWalletType.CAT_WALLET,
3626
+ mode=WalletCreationMode.NEW,
3627
+ amount=uint64(100),
3628
+ test=True,
3629
+ push=True,
3630
+ ),
3631
+ tx_config=wallet_environments.tx_config,
3632
+ )
3633
+ await client.create_new_wallet(
3634
+ CreateNewWallet(
3635
+ wallet_type=CreateNewWalletType.CAT_WALLET,
3636
+ mode=WalletCreationMode.NEW,
3637
+ amount=uint64(20),
3638
+ test=True,
3639
+ push=True,
3640
+ ),
3641
+ tx_config=wallet_environments.tx_config,
3642
+ )
3643
+ await wallet_environments.process_pending_states(
3644
+ [
3645
+ WalletStateTransition(
3646
+ pre_block_balance_updates={
3647
+ "xch": {"set_remainder": True},
3648
+ "cat": {"init": True, "set_remainder": True},
3649
+ "cat2": {"init": True, "set_remainder": True},
3650
+ },
3651
+ post_block_balance_updates={
3652
+ "xch": {"set_remainder": True},
3653
+ "cat": {"set_remainder": True},
3654
+ "cat2": {"set_remainder": True},
3655
+ },
3656
+ ),
3657
+ WalletStateTransition(),
3658
+ ]
3659
+ )
3219
3660
  bals_response = await client.get_wallet_balances(GetWalletBalances())
3220
3661
  assert len(bals_response.wallet_balances) == 3
3221
3662
  assert bals_response.wallet_balances[uint32(1)].confirmed_wallet_balance == 1999999999880
@@ -3265,9 +3706,12 @@ async def test_split_coins(wallet_environments: WalletTestFramework, capsys: pyt
3265
3706
  }
3266
3707
  )
3267
3708
 
3268
- with pytest.raises(ResponseFailureError, match="501 coins is greater then the maximum limit of 500 coins"):
3709
+ with pytest.raises(ValueError, match="501 coins is greater then the maximum limit of 500 coins"):
3269
3710
  await dataclasses.replace(xch_request, number_of_coins=501).run()
3270
3711
 
3712
+ with pytest.raises(ValueError, match="Cannot split into 0 new coins"):
3713
+ await dataclasses.replace(xch_request, number_of_coins=0).run()
3714
+
3271
3715
  with pytest.raises(ResponseFailureError, match="Could not find coin with ID 00000000000000000"):
3272
3716
  await dataclasses.replace(xch_request, target_coin_id=bytes32.zeros).run()
3273
3717
 
@@ -3298,10 +3742,6 @@ async def test_split_coins(wallet_environments: WalletTestFramework, capsys: pyt
3298
3742
 
3299
3743
  del env.wallet_state_manager.wallets[uint32(42)]
3300
3744
 
3301
- await dataclasses.replace(xch_request, number_of_coins=0).run()
3302
- output = (capsys.readouterr()).out
3303
- assert "Transaction sent" not in output
3304
-
3305
3745
  with wallet_environments.new_puzzle_hashes_allowed():
3306
3746
  await xch_request.run()
3307
3747
 
@@ -3461,13 +3901,13 @@ async def test_combine_coins(wallet_environments: WalletTestFramework, capsys: p
3461
3901
  )
3462
3902
 
3463
3903
  # Test some error cases first
3464
- with pytest.raises(ResponseFailureError, match="greater then the maximum limit"):
3904
+ with pytest.raises(ValueError, match="greater then the maximum limit"):
3465
3905
  await dataclasses.replace(xch_combine_request, number_of_coins=uint16(501)).run()
3466
3906
 
3467
- with pytest.raises(ResponseFailureError, match="You need at least two coins to combine"):
3907
+ with pytest.raises(ValueError, match="You need at least two coins to combine"):
3468
3908
  await dataclasses.replace(xch_combine_request, number_of_coins=uint16(0)).run()
3469
3909
 
3470
- with pytest.raises(ResponseFailureError, match="More coin IDs specified than desired number of coins to combine"):
3910
+ with pytest.raises(ValueError, match="More coin IDs specified than desired number of coins to combine"):
3471
3911
  await dataclasses.replace(xch_combine_request, input_coins=(bytes32.zeros,) * 100).run()
3472
3912
 
3473
3913
  # We catch this one
@@ -3718,3 +4158,339 @@ async def test_fee_bigger_than_selection_coin_combining(wallet_environments: Wal
3718
4158
  )
3719
4159
  ]
3720
4160
  )
4161
+
4162
+
4163
+ def test_send_transaction_multi_post_init() -> None:
4164
+ with pytest.raises(
4165
+ ValueError,
4166
+ match=re.escape('Specified "morph_bytes" for a CAT-type wallet. Maybe you meant to specify an XCH wallet?'),
4167
+ ):
4168
+ SendTransactionMulti(
4169
+ wallet_id=uint32(1),
4170
+ morph_bytes=b"",
4171
+ ).convert_to_proxy(CATSpend)
4172
+
4173
+ with pytest.raises(
4174
+ ValueError,
4175
+ match=re.escape(
4176
+ 'Specified "coin/puzzle_announcements" for a CAT-type wallet.Maybe you meant to specify an XCH wallet?'
4177
+ ),
4178
+ ):
4179
+ SendTransactionMulti(
4180
+ wallet_id=uint32(1),
4181
+ coin_announcements=[],
4182
+ ).convert_to_proxy(CATSpend)
4183
+
4184
+ with pytest.raises(
4185
+ ValueError,
4186
+ match=re.escape(
4187
+ 'Specified "coin/puzzle_announcements" for a CAT-type wallet.Maybe you meant to specify an XCH wallet?'
4188
+ ),
4189
+ ):
4190
+ SendTransactionMulti(
4191
+ wallet_id=uint32(1),
4192
+ puzzle_announcements=[],
4193
+ ).convert_to_proxy(CATSpend)
4194
+
4195
+ with pytest.raises(
4196
+ ValueError,
4197
+ match=re.escape('Specified "amount" for an XCH wallet. Maybe you meant to specify a CAT-type wallet?'),
4198
+ ):
4199
+ SendTransactionMulti(
4200
+ wallet_id=uint32(1),
4201
+ amount=uint64(100),
4202
+ ).convert_to_proxy(CreateSignedTransaction)
4203
+
4204
+ with pytest.raises(
4205
+ ValueError,
4206
+ match=re.escape('Specified "inner_address" for an XCH wallet. Maybe you meant to specify a CAT-type wallet?'),
4207
+ ):
4208
+ SendTransactionMulti(
4209
+ wallet_id=uint32(1),
4210
+ inner_address="foo",
4211
+ ).convert_to_proxy(CreateSignedTransaction)
4212
+
4213
+ with pytest.raises(
4214
+ ValueError,
4215
+ match=re.escape('Specified "memos" for an XCH wallet. Maybe you meant to specify a CAT-type wallet?'),
4216
+ ):
4217
+ SendTransactionMulti(
4218
+ wallet_id=uint32(1),
4219
+ memos=["foo"],
4220
+ ).convert_to_proxy(CreateSignedTransaction)
4221
+
4222
+ with pytest.raises(
4223
+ ValueError,
4224
+ match=re.escape(
4225
+ 'Specified "extra_delta", "tail_reveal", or "tail_solution" for an XCH wallet.'
4226
+ "Maybe you meant to specify a CAT-type wallet?"
4227
+ ),
4228
+ ):
4229
+ SendTransactionMulti(
4230
+ wallet_id=uint32(1),
4231
+ extra_delta="1",
4232
+ ).convert_to_proxy(CreateSignedTransaction)
4233
+
4234
+ with pytest.raises(
4235
+ ValueError,
4236
+ match=re.escape(
4237
+ 'Specified "extra_delta", "tail_reveal", or "tail_solution" for an XCH wallet.'
4238
+ "Maybe you meant to specify a CAT-type wallet?"
4239
+ ),
4240
+ ):
4241
+ SendTransactionMulti(
4242
+ wallet_id=uint32(1),
4243
+ tail_reveal=b"",
4244
+ ).convert_to_proxy(CreateSignedTransaction)
4245
+
4246
+ with pytest.raises(
4247
+ ValueError,
4248
+ match=re.escape(
4249
+ 'Specified "extra_delta", "tail_reveal", or "tail_solution" for an XCH wallet.'
4250
+ "Maybe you meant to specify a CAT-type wallet?"
4251
+ ),
4252
+ ):
4253
+ SendTransactionMulti(
4254
+ wallet_id=uint32(1),
4255
+ tail_solution=b"",
4256
+ ).convert_to_proxy(CreateSignedTransaction)
4257
+
4258
+ with pytest.raises(
4259
+ ValueError,
4260
+ match=re.escape('"additions" are required for XCH wallets.'),
4261
+ ):
4262
+ SendTransactionMulti(
4263
+ wallet_id=uint32(1),
4264
+ ).convert_to_proxy(CreateSignedTransaction)
4265
+
4266
+ with pytest.raises(
4267
+ ValueError,
4268
+ match=re.escape("An unsupported wallet type was selected for `send_transaction_multi`"),
4269
+ ):
4270
+ SendTransactionMulti( # type: ignore[type-var]
4271
+ wallet_id=uint32(1),
4272
+ ).convert_to_proxy(VCSpend)
4273
+
4274
+
4275
+ def test_create_new_wallet_post_init() -> None:
4276
+ with pytest.raises(
4277
+ ValueError,
4278
+ match=re.escape("Invalid pool wallet initial state: FOO"),
4279
+ ):
4280
+ NewPoolWalletInitialTargetState(state="FOO")
4281
+
4282
+ with pytest.raises(
4283
+ ValueError,
4284
+ match=re.escape("target_puzzle_hash must be set when state is FARMING_TO_POOL"),
4285
+ ):
4286
+ NewPoolWalletInitialTargetState(state="FARMING_TO_POOL")
4287
+
4288
+ with pytest.raises(
4289
+ ValueError,
4290
+ match=re.escape("pool_url must be set when state is FARMING_TO_POOL"),
4291
+ ):
4292
+ NewPoolWalletInitialTargetState(state="FARMING_TO_POOL", target_puzzle_hash=bytes32.zeros)
4293
+
4294
+ with pytest.raises(
4295
+ ValueError,
4296
+ match=re.escape("relative_lock_height must be set when state is FARMING_TO_POOL"),
4297
+ ):
4298
+ NewPoolWalletInitialTargetState(state="FARMING_TO_POOL", target_puzzle_hash=bytes32.zeros, pool_url="")
4299
+
4300
+ with pytest.raises(
4301
+ ValueError,
4302
+ match=re.escape("target_puzzle_hash is only valid for FARMING_TO_POOL"),
4303
+ ):
4304
+ NewPoolWalletInitialTargetState(state="SELF_POOLING", target_puzzle_hash=bytes32.zeros)
4305
+
4306
+ with pytest.raises(
4307
+ ValueError,
4308
+ match=re.escape("pool_url is only valid for FARMING_TO_POOL"),
4309
+ ):
4310
+ NewPoolWalletInitialTargetState(state="SELF_POOLING", pool_url="")
4311
+
4312
+ with pytest.raises(
4313
+ ValueError,
4314
+ match=re.escape("relative_lock_height is only valid for FARMING_TO_POOL"),
4315
+ ):
4316
+ NewPoolWalletInitialTargetState(state="SELF_POOLING", relative_lock_height=uint32(0))
4317
+
4318
+ with pytest.raises(
4319
+ ValueError,
4320
+ match=re.escape('Must specify a "mode" when creating a new CAT wallet'),
4321
+ ):
4322
+ CreateNewWallet(wallet_type=CreateNewWalletType.CAT_WALLET)
4323
+
4324
+ with pytest.raises(
4325
+ ValueError,
4326
+ match=re.escape("Support for this RPC mode has been dropped."),
4327
+ ):
4328
+ CreateNewWallet(wallet_type=CreateNewWalletType.CAT_WALLET, mode=WalletCreationMode.NEW)
4329
+
4330
+ with pytest.raises(
4331
+ ValueError,
4332
+ match=re.escape('Must specify an "amount" of CATs to generate'),
4333
+ ):
4334
+ CreateNewWallet(wallet_type=CreateNewWalletType.CAT_WALLET, mode=WalletCreationMode.NEW, test=True)
4335
+
4336
+ with pytest.raises(
4337
+ ValueError,
4338
+ match=re.escape('"asset_id" is not an argument for new CAT wallets. Maybe you meant existing?'),
4339
+ ):
4340
+ CreateNewWallet(
4341
+ wallet_type=CreateNewWalletType.CAT_WALLET,
4342
+ mode=WalletCreationMode.NEW,
4343
+ test=True,
4344
+ amount=uint64(0),
4345
+ asset_id=bytes32.zeros,
4346
+ )
4347
+
4348
+ with pytest.raises(
4349
+ ValueError,
4350
+ match=re.escape('Must specify an "asset_id" when creating an existing CAT wallet'),
4351
+ ):
4352
+ CreateNewWallet(wallet_type=CreateNewWalletType.CAT_WALLET, mode=WalletCreationMode.EXISTING)
4353
+
4354
+ with pytest.raises(
4355
+ ValueError,
4356
+ match=re.escape('"amount" is not an argument for existing CAT wallets'),
4357
+ ):
4358
+ CreateNewWallet(
4359
+ wallet_type=CreateNewWalletType.CAT_WALLET,
4360
+ mode=WalletCreationMode.EXISTING,
4361
+ asset_id=bytes32.zeros,
4362
+ amount=uint64(0),
4363
+ )
4364
+
4365
+ with pytest.raises(
4366
+ ValueError,
4367
+ match=re.escape('"test" mode is not supported except for new CAT wallets'),
4368
+ ):
4369
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, test=True)
4370
+
4371
+ with pytest.raises(
4372
+ ValueError,
4373
+ match=re.escape('"asset_id" is not a valid argument. Maybe you meant to create an existing CAT wallet?'),
4374
+ ):
4375
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, asset_id=bytes32.zeros)
4376
+
4377
+ with pytest.raises(
4378
+ ValueError,
4379
+ match=re.escape('"mode": "existing" is only valid for CAT wallets'),
4380
+ ):
4381
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, mode=WalletCreationMode.EXISTING)
4382
+
4383
+ with pytest.raises(
4384
+ ValueError,
4385
+ match=re.escape('Must specify "did_type": "new/recovery"'),
4386
+ ):
4387
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET)
4388
+
4389
+ with pytest.raises(
4390
+ ValueError,
4391
+ match=re.escape('Must specify an "amount" when creating a new DID'),
4392
+ ):
4393
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, did_type=DIDType.NEW)
4394
+
4395
+ with pytest.raises(
4396
+ ValueError,
4397
+ match=re.escape('Recovery options are no longer supported. "backup_dids" cannot be set.'),
4398
+ ):
4399
+ CreateNewWallet(
4400
+ wallet_type=CreateNewWalletType.DID_WALLET, did_type=DIDType.NEW, amount=uint64(0), backup_dids=["foo"]
4401
+ )
4402
+
4403
+ with pytest.raises(
4404
+ ValueError,
4405
+ match=re.escape('"backup_data" is only an option in "did_type": "recovery"'),
4406
+ ):
4407
+ CreateNewWallet(
4408
+ wallet_type=CreateNewWalletType.DID_WALLET, did_type=DIDType.NEW, amount=uint64(0), backup_data="foo"
4409
+ )
4410
+
4411
+ with pytest.raises(
4412
+ ValueError,
4413
+ match=re.escape('Cannot specify an "amount" when recovering a DID'),
4414
+ ):
4415
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, did_type=DIDType.RECOVERY, amount=uint64(0))
4416
+
4417
+ with pytest.raises(
4418
+ ValueError,
4419
+ match=re.escape('Cannot specify "backup_dids" when recovering a DID'),
4420
+ ):
4421
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, did_type=DIDType.RECOVERY, backup_dids=["foo"])
4422
+
4423
+ with pytest.raises(
4424
+ ValueError,
4425
+ match=re.escape('Cannot specify "metadata" when recovering a DID'),
4426
+ ):
4427
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, did_type=DIDType.RECOVERY, metadata={"foo": "bar"})
4428
+
4429
+ with pytest.raises(
4430
+ ValueError,
4431
+ match=re.escape('Must specify "backup_data" when recovering a DID'),
4432
+ ):
4433
+ CreateNewWallet(wallet_type=CreateNewWalletType.DID_WALLET, did_type=DIDType.RECOVERY)
4434
+
4435
+ with pytest.raises(
4436
+ ValueError,
4437
+ match=re.escape('"did_type" is only a valid argument for DID wallets'),
4438
+ ):
4439
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, did_type=DIDType.NEW)
4440
+
4441
+ with pytest.raises(
4442
+ ValueError,
4443
+ match=re.escape('"backup_dids" is only a valid argument for DID wallets'),
4444
+ ):
4445
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, backup_dids=["foo"])
4446
+
4447
+ with pytest.raises(
4448
+ ValueError,
4449
+ match=re.escape('"metadata" is only a valid argument for DID wallets'),
4450
+ ):
4451
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, metadata={"foo": "bar"})
4452
+
4453
+ with pytest.raises(
4454
+ ValueError,
4455
+ match=re.escape('"wallet_name" is only a valid argument for DID wallets'),
4456
+ ):
4457
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, wallet_name="foo")
4458
+
4459
+ with pytest.raises(
4460
+ ValueError,
4461
+ match=re.escape('"backup_data" is only a valid argument for DID wallets'),
4462
+ ):
4463
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, backup_data="foo")
4464
+
4465
+ with pytest.raises(
4466
+ ValueError,
4467
+ match=re.escape('"did_id" is only a valid argument for NFT wallets'),
4468
+ ):
4469
+ CreateNewWallet(wallet_type=CreateNewWalletType.POOL_WALLET, did_id="foo")
4470
+
4471
+ with pytest.raises(
4472
+ ValueError,
4473
+ match=re.escape('"initial_target_state" is required for new pool wallets'),
4474
+ ):
4475
+ CreateNewWallet(wallet_type=CreateNewWalletType.POOL_WALLET)
4476
+
4477
+ with pytest.raises(
4478
+ ValueError,
4479
+ match=re.escape('"initial_target_state" is only a valid argument for pool wallets'),
4480
+ ):
4481
+ CreateNewWallet(
4482
+ wallet_type=CreateNewWalletType.NFT_WALLET,
4483
+ initial_target_state=NewPoolWalletInitialTargetState("SELF_POOLING"),
4484
+ )
4485
+
4486
+ with pytest.raises(
4487
+ ValueError,
4488
+ match=re.escape('"p2_singleton_delayed_ph" is only a valid argument for pool wallets'),
4489
+ ):
4490
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, p2_singleton_delayed_ph=bytes32.zeros)
4491
+
4492
+ with pytest.raises(
4493
+ ValueError,
4494
+ match=re.escape('"p2_singleton_delay_time" is only a valid argument for pool wallets'),
4495
+ ):
4496
+ CreateNewWallet(wallet_type=CreateNewWalletType.NFT_WALLET, p2_singleton_delay_time=uint64(0))