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
@@ -7,15 +7,15 @@ import logging
7
7
  import multiprocessing.context
8
8
  import time
9
9
  import traceback
10
- from collections.abc import AsyncIterator
10
+ from collections.abc import AsyncIterator, Callable
11
11
  from contextlib import asynccontextmanager
12
12
  from pathlib import Path
13
- from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, cast
13
+ from typing import TYPE_CHECKING, Any, Literal, TypeVar, cast
14
14
 
15
15
  import aiosqlite
16
- from chia_rs import AugSchemeMPL, CoinSpend, CoinState, ConsensusConstants, G1Element, G2Element, PrivateKey
16
+ from chia_rs import AugSchemeMPL, CoinRecord, CoinSpend, CoinState, ConsensusConstants, G1Element, G2Element, PrivateKey
17
17
  from chia_rs.sized_bytes import bytes32
18
- from chia_rs.sized_ints import uint16, uint32, uint64, uint128
18
+ from chia_rs.sized_ints import uint8, uint16, uint32, uint64, uint128
19
19
 
20
20
  from chia.consensus.block_rewards import calculate_base_farmer_reward, calculate_pool_reward
21
21
  from chia.consensus.coinbase import farmer_parent_id, pool_parent_id
@@ -33,8 +33,7 @@ from chia.rpc.rpc_server import StateChangedProtocol
33
33
  from chia.server.server import ChiaServer
34
34
  from chia.server.ws_connection import WSChiaConnection
35
35
  from chia.types.blockchain_format.coin import Coin
36
- from chia.types.blockchain_format.program import NIL, Program
37
- from chia.types.coin_record import CoinRecord
36
+ from chia.types.blockchain_format.program import Program
38
37
  from chia.types.mempool_inclusion_status import MempoolInclusionStatus
39
38
  from chia.util.bech32m import encode_puzzle_hash
40
39
  from chia.util.db_synchronous import db_synchronous_on
@@ -60,10 +59,12 @@ from chia.wallet.conditions import (
60
59
  from chia.wallet.db_wallet.db_wallet_puzzles import MIRROR_PUZZLE_HASH
61
60
  from chia.wallet.derivation_record import DerivationRecord
62
61
  from chia.wallet.derive_keys import (
62
+ MAX_POOL_WALLETS,
63
63
  _derive_path,
64
64
  _derive_pk_unhardened,
65
65
  master_pk_to_wallet_pk_unhardened,
66
66
  master_pk_to_wallet_pk_unhardened_intermediate,
67
+ master_sk_to_singleton_owner_sk,
67
68
  master_sk_to_wallet_sk,
68
69
  master_sk_to_wallet_sk_intermediate,
69
70
  master_sk_to_wallet_sk_unhardened,
@@ -105,7 +106,7 @@ from chia.wallet.util.compute_hints import compute_spend_hints_and_additions
105
106
  from chia.wallet.util.compute_memos import compute_memos
106
107
  from chia.wallet.util.curry_and_treehash import NIL_TREEHASH
107
108
  from chia.wallet.util.puzzle_decorator import PuzzleDecoratorManager
108
- from chia.wallet.util.query_filter import HashFilter
109
+ from chia.wallet.util.query_filter import FilterMode, HashFilter
109
110
  from chia.wallet.util.transaction_type import CLAWBACK_INCOMING_TRANSACTION_TYPES, TransactionType
110
111
  from chia.wallet.util.tx_config import TXConfig, TXConfigLoader
111
112
  from chia.wallet.util.wallet_sync_utils import (
@@ -123,7 +124,7 @@ from chia.wallet.wallet import Wallet
123
124
  from chia.wallet.wallet_action_scope import WalletActionScope, new_wallet_action_scope
124
125
  from chia.wallet.wallet_blockchain import WalletBlockchain
125
126
  from chia.wallet.wallet_coin_record import MetadataTypes, WalletCoinRecord
126
- from chia.wallet.wallet_coin_store import WalletCoinStore
127
+ from chia.wallet.wallet_coin_store import CoinRecordOrder, WalletCoinStore
127
128
  from chia.wallet.wallet_info import WalletInfo
128
129
  from chia.wallet.wallet_interested_store import WalletInterestedStore
129
130
  from chia.wallet.wallet_nft_store import WalletNftStore
@@ -165,16 +166,16 @@ class WalletStateManager:
165
166
  log: logging.Logger
166
167
 
167
168
  # TODO Don't allow user to send tx until wallet is synced
168
- _sync_target: Optional[uint32]
169
+ _sync_target: uint32 | None
169
170
 
170
- state_changed_callback: Optional[StateChangedProtocol] = None
171
- pending_tx_callback: Optional[PendingTxCallback]
171
+ state_changed_callback: StateChangedProtocol | None = None
172
+ pending_tx_callback: PendingTxCallback | None
172
173
  db_path: Path
173
174
  db_wrapper: DBWrapper2
174
175
 
175
176
  main_wallet: Wallet
176
177
  wallets: dict[uint32, WalletProtocol[Any]]
177
- private_key: Optional[PrivateKey]
178
+ private_key: PrivateKey | None
178
179
  root_pubkey: G1Element
179
180
 
180
181
  trade_manager: TradeManager
@@ -196,14 +197,14 @@ class WalletStateManager:
196
197
 
197
198
  @staticmethod
198
199
  async def create(
199
- private_key: Optional[PrivateKey],
200
+ private_key: PrivateKey | None,
200
201
  config: dict[str, Any],
201
202
  db_path: Path,
202
203
  constants: ConsensusConstants,
203
204
  server: ChiaServer,
204
205
  root_path: Path,
205
206
  wallet_node: WalletNode,
206
- root_pubkey: Optional[G1Element] = None,
207
+ root_pubkey: G1Element | None = None,
207
208
  ) -> WalletStateManager:
208
209
  self = WalletStateManager()
209
210
 
@@ -214,7 +215,7 @@ class WalletStateManager:
214
215
  self.log = logging.getLogger(__name__)
215
216
  self.lock = asyncio.Lock()
216
217
  self.log.debug(f"Starting in db path: {db_path}")
217
- sql_log_path: Optional[Path] = None
218
+ sql_log_path: Path | None = None
218
219
  if self.config.get("log_sqlite_cmds", False):
219
220
  sql_log_path = path_from_root(self.root_path, "log/wallet_sql.log")
220
221
  self.log.info(f"logging SQL commands to {sql_log_path}")
@@ -280,7 +281,7 @@ class WalletStateManager:
280
281
  AssetType.CAT: CATWallet,
281
282
  }
282
283
 
283
- wallet: Optional[WalletProtocol[Any]] = None
284
+ wallet: WalletProtocol[Any] | None = None
284
285
  for wallet_info in await self.get_all_wallet_info_entries():
285
286
  wallet_type = WalletType(wallet_info.type)
286
287
  if wallet_type == WalletType.STANDARD_WALLET:
@@ -367,9 +368,13 @@ class WalletStateManager:
367
368
  return self.private_key
368
369
 
369
370
  def get_wallet(self, id: uint32, required_type: type[TWalletType]) -> TWalletType:
371
+ if id not in self.wallets:
372
+ raise ValueError(f"Wallet with id {id} does not exist")
373
+
370
374
  wallet = self.wallets[id]
375
+
371
376
  if not isinstance(wallet, required_type):
372
- raise Exception(
377
+ raise ValueError(
373
378
  f"wallet id {id} is of type {type(wallet).__name__} but type {required_type.__name__} is required",
374
379
  )
375
380
 
@@ -389,9 +394,9 @@ class WalletStateManager:
389
394
  self,
390
395
  from_zero: bool = False,
391
396
  mark_existing_as_used: bool = True,
392
- up_to_index: Optional[uint32] = None,
393
- num_additional_phs: Optional[int] = None,
394
- previous_result: Optional[CreateMorePuzzleHashesResult] = None,
397
+ up_to_index: uint32 | None = None,
398
+ num_additional_phs: int | None = None,
399
+ previous_result: CreateMorePuzzleHashesResult | None = None,
395
400
  _commit_previous_result: bool = True,
396
401
  ) -> CreateMorePuzzleHashesResult:
397
402
  """
@@ -408,8 +413,8 @@ class WalletStateManager:
408
413
  if _commit_previous_result:
409
414
  await previous_result.commit(self)
410
415
  targets = list(self.wallets.keys())
411
- self.log.debug("Target wallets to generate puzzle hashes for: %s", repr(targets))
412
- unused: Optional[uint32] = (
416
+ self.log.debug("Target wallets to generate puzzle hashes for: %r", targets)
417
+ unused: uint32 | None = (
413
418
  up_to_index if up_to_index is not None else await self.puzzle_store.get_unused_derivation_path()
414
419
  )
415
420
  if unused is None:
@@ -439,7 +444,7 @@ class WalletStateManager:
439
444
  if from_zero:
440
445
  start_index_by_wallet[wallet_id] = 0
441
446
  continue
442
- last: Optional[uint32] = await self.puzzle_store.get_last_derivation_path_for_wallet(wallet_id)
447
+ last: uint32 | None = await self.puzzle_store.get_last_derivation_path_for_wallet(wallet_id)
443
448
  if last is not None:
444
449
  if last >= last_index:
445
450
  self.log.debug(f"Nothing to create for for wallet_id: {wallet_id}, index: {last_index}")
@@ -490,7 +495,7 @@ class WalletStateManager:
490
495
  )
491
496
  self.log.info(f"Start: {creating_msg}")
492
497
  for index in range(start_index, last_index + 1):
493
- pubkey: Optional[G1Element] = hardened_keys.get(index)
498
+ pubkey: G1Element | None = hardened_keys.get(index)
494
499
  if pubkey is not None:
495
500
  # Hardened
496
501
  puzzlehash: bytes32 = target_wallet.puzzle_hash_for_pk(pubkey)
@@ -540,8 +545,8 @@ class WalletStateManager:
540
545
  async def update_wallet_puzzle_hashes(self, wallet_id: uint32) -> None:
541
546
  derivation_paths: list[DerivationRecord] = []
542
547
  target_wallet = self.wallets[wallet_id]
543
- last: Optional[uint32] = await self.puzzle_store.get_last_derivation_path_for_wallet(wallet_id)
544
- unused: Optional[uint32] = await self.puzzle_store.get_unused_derivation_path_for_wallet(wallet_id)
548
+ last: uint32 | None = await self.puzzle_store.get_last_derivation_path_for_wallet(wallet_id)
549
+ unused: uint32 | None = await self.puzzle_store.get_unused_derivation_path_for_wallet(wallet_id)
545
550
  if unused is None:
546
551
  # This handles the case where the database has entries but they have all been used
547
552
  unused = await self.puzzle_store.get_last_derivation_path()
@@ -571,7 +576,7 @@ class WalletStateManager:
571
576
  wallet_id: uint32,
572
577
  *,
573
578
  hardened: bool = False,
574
- previous_result: Optional[GetUnusedDerivationRecordResult] = None,
579
+ previous_result: GetUnusedDerivationRecordResult | None = None,
575
580
  ) -> GetUnusedDerivationRecordResult:
576
581
  """
577
582
  Creates a puzzle hash for the given wallet, and then makes more puzzle hashes
@@ -582,13 +587,13 @@ class WalletStateManager:
582
587
  async with self.puzzle_hash_db_writer():
583
588
  if previous_result is not None:
584
589
  await previous_result.commit(self)
585
- create_more_puzzle_hashes_result: Optional[CreateMorePuzzleHashesResult] = (
590
+ create_more_puzzle_hashes_result: CreateMorePuzzleHashesResult | None = (
586
591
  previous_result.create_more_puzzle_hashes_result
587
592
  )
588
593
  else:
589
594
  create_more_puzzle_hashes_result = None
590
595
  # If we have no unused public keys, we will create new ones
591
- unused: Optional[uint32] = await self.puzzle_store.get_unused_derivation_path()
596
+ unused: uint32 | None = await self.puzzle_store.get_unused_derivation_path()
592
597
  if unused is None:
593
598
  self.log.debug("No unused paths, generate more ")
594
599
  create_more_puzzle_hashes_result = await self.create_more_puzzle_hashes(
@@ -600,7 +605,7 @@ class WalletStateManager:
600
605
  assert unused is not None
601
606
 
602
607
  self.log.debug("Fetching derivation record for: %s %s %s", unused, wallet_id, hardened)
603
- record: Optional[DerivationRecord] = await self.puzzle_store.get_derivation_record(
608
+ record: DerivationRecord | None = await self.puzzle_store.get_derivation_record(
604
609
  unused, wallet_id, hardened
605
610
  )
606
611
  if record is None:
@@ -625,10 +630,10 @@ class WalletStateManager:
625
630
  await result.commit(self)
626
631
  return result.record
627
632
 
628
- async def get_current_derivation_record_for_wallet(self, wallet_id: uint32) -> Optional[DerivationRecord]:
633
+ async def get_current_derivation_record_for_wallet(self, wallet_id: uint32) -> DerivationRecord | None:
629
634
  async with self.puzzle_store.lock:
630
635
  # If we have no unused public keys, we will create new ones
631
- current: Optional[DerivationRecord] = await self.puzzle_store.get_current_derivation_record_for_wallet(
636
+ current: DerivationRecord | None = await self.puzzle_store.get_current_derivation_record_for_wallet(
632
637
  wallet_id
633
638
  )
634
639
  return current
@@ -646,7 +651,7 @@ class WalletStateManager:
646
651
  self.pending_tx_callback = callback
647
652
 
648
653
  def state_changed(
649
- self, state: str, wallet_id: Optional[int] = None, data_object: Optional[dict[str, Any]] = None
654
+ self, state: str, wallet_id: int | None = None, data_object: dict[str, Any] | None = None
650
655
  ) -> None:
651
656
  """
652
657
  Calls the callback if it's present.
@@ -669,7 +674,7 @@ class WalletStateManager:
669
674
 
670
675
  self.pending_tx_callback()
671
676
 
672
- async def synced(self, block_is_current_at: Optional[int] = None) -> bool:
677
+ async def synced(self, block_is_current_at: int | None = None) -> bool:
673
678
  if block_is_current_at is None:
674
679
  block_is_current_at = int(time.time() - 60 * 5)
675
680
  if len(self.server.get_connections(NodeType.FULL_NODE)) == 0:
@@ -697,7 +702,7 @@ class WalletStateManager:
697
702
  return self._sync_target is not None
698
703
 
699
704
  @property
700
- def sync_target(self) -> Optional[uint32]:
705
+ def sync_target(self) -> uint32 | None:
701
706
  return self._sync_target
702
707
 
703
708
  @asynccontextmanager
@@ -727,7 +732,7 @@ class WalletStateManager:
727
732
  self._sync_target = None
728
733
 
729
734
  async def get_confirmed_spendable_balance_for_wallet(
730
- self, wallet_id: int, unspent_records: Optional[set[WalletCoinRecord]] = None
735
+ self, wallet_id: int, unspent_records: set[WalletCoinRecord] | None = None
731
736
  ) -> uint128:
732
737
  """
733
738
  Returns the balance amount of all coins that are spendable.
@@ -753,7 +758,7 @@ class WalletStateManager:
753
758
  async def get_confirmed_balance_for_wallet(
754
759
  self,
755
760
  wallet_id: int,
756
- unspent_coin_records: Optional[set[WalletCoinRecord]] = None,
761
+ unspent_coin_records: set[WalletCoinRecord] | None = None,
757
762
  ) -> uint128:
758
763
  """
759
764
  Returns the confirmed balance, including coinbase rewards that are not spendable.
@@ -768,7 +773,7 @@ class WalletStateManager:
768
773
  return uint128(sum(cr.coin.amount for cr in unspent_coin_records))
769
774
 
770
775
  async def get_unconfirmed_balance(
771
- self, wallet_id: int, unspent_coin_records: Optional[set[WalletCoinRecord]] = None
776
+ self, wallet_id: int, unspent_coin_records: set[WalletCoinRecord] | None = None
772
777
  ) -> uint128:
773
778
  """
774
779
  Returns the balance, including coinbase rewards that are not spendable, and unconfirmed
@@ -825,8 +830,8 @@ class WalletStateManager:
825
830
  return {**removals, **{coin_id: cr.coin for coin_id, cr in trade_removals.items() if cr.wallet_id == wallet_id}}
826
831
 
827
832
  async def determine_coin_type(
828
- self, peer: WSChiaConnection, coin_state: CoinState, fork_height: Optional[uint32]
829
- ) -> tuple[Optional[WalletIdentifier], Optional[Streamable]]:
833
+ self, peer: WSChiaConnection, coin_state: CoinState, fork_height: uint32 | None
834
+ ) -> tuple[WalletIdentifier | None, Streamable | None]:
830
835
  if coin_state.created_height is not None and (
831
836
  self.is_pool_reward(uint32(coin_state.created_height), coin_state.coin)
832
837
  or self.is_farmer_reward(uint32(coin_state.created_height), coin_state.coin)
@@ -883,7 +888,7 @@ class WalletStateManager:
883
888
  p2_puzzle, recovery_list_hash, num_verification, singleton_struct, metadata = did_curried_args
884
889
  did_data: DIDCoinData = DIDCoinData(
885
890
  p2_puzzle,
886
- bytes32(recovery_list_hash.as_atom()) if recovery_list_hash != Program.to(None) else None,
891
+ bytes32(recovery_list_hash.as_atom()) if recovery_list_hash != Program.NIL else None,
887
892
  uint16(num_verification.as_int()),
888
893
  singleton_struct,
889
894
  metadata,
@@ -964,7 +969,7 @@ class WalletStateManager:
964
969
  coin_spends: list[CoinSpend] = []
965
970
  message: bytes32 = std_hash(b"".join([c.name() for c in clawback_coins.keys()]))
966
971
  now: uint64 = uint64(time.time())
967
- derivation_record: Optional[DerivationRecord] = None
972
+ derivation_record: DerivationRecord | None = None
968
973
  amount: uint64 = uint64(0)
969
974
  for coin, metadata in clawback_coins.items():
970
975
  try:
@@ -1113,8 +1118,8 @@ class WalletStateManager:
1113
1118
  coin_state: CoinState,
1114
1119
  coin_spend: CoinSpend,
1115
1120
  peer: WSChiaConnection,
1116
- fork_height: Optional[uint32],
1117
- ) -> Optional[WalletIdentifier]:
1121
+ fork_height: uint32 | None,
1122
+ ) -> WalletIdentifier | None:
1118
1123
  """
1119
1124
  Handle the new coin when it is a CAT
1120
1125
  :param parent_data: Parent CAT coin uncurried metadata
@@ -1210,7 +1215,7 @@ class WalletStateManager:
1210
1215
  cat_wallet: CATWallet = await CRCATWallet.get_or_create_wallet_for_cat(
1211
1216
  self,
1212
1217
  self.main_wallet,
1213
- crcat.tail_hash.hex(),
1218
+ crcat.tail_hash,
1214
1219
  authorized_providers=crcat.authorized_providers,
1215
1220
  proofs_checker=ProofsChecker.from_program(uncurry_puzzle(crcat.proofs_checker)),
1216
1221
  )
@@ -1218,20 +1223,20 @@ class WalletStateManager:
1218
1223
  cat_wallet = await RCATWallet.get_or_create_wallet_for_cat(
1219
1224
  self,
1220
1225
  self.main_wallet,
1221
- parent_data.tail_program_hash.hex(),
1226
+ parent_data.tail_program_hash,
1222
1227
  # too complicated for mypy but semantics guarantee this not to be None
1223
1228
  hidden_puzzle_hash=revocation_layer_match[0], # type: ignore[index]
1224
1229
  )
1225
1230
  else:
1226
1231
  cat_wallet = await CATWallet.get_or_create_wallet_for_cat(
1227
- self, self.main_wallet, parent_data.tail_program_hash.hex()
1232
+ self, self.main_wallet, parent_data.tail_program_hash
1228
1233
  )
1229
1234
  return WalletIdentifier.create(cat_wallet)
1230
1235
  else:
1231
1236
  # Found unacknowledged CAT, save it in the database.
1232
1237
  await self.interested_store.add_unacknowledged_token(
1233
1238
  asset_id,
1234
- CATWallet.default_wallet_name_for_unknown_cat(asset_id.hex()),
1239
+ CATWallet.default_wallet_name_for_unknown_cat(asset_id),
1235
1240
  None if parent_coin_state.spent_height is None else uint32(parent_coin_state.spent_height),
1236
1241
  parent_coin_state.coin.puzzle_hash,
1237
1242
  )
@@ -1250,7 +1255,7 @@ class WalletStateManager:
1250
1255
  coin_state: CoinState,
1251
1256
  coin_spend: CoinSpend,
1252
1257
  peer: WSChiaConnection,
1253
- ) -> Optional[WalletIdentifier]:
1258
+ ) -> WalletIdentifier | None:
1254
1259
  """
1255
1260
  Handle the new coin when it is a DID
1256
1261
  :param parent_data: Curried data of the DID coin
@@ -1309,7 +1314,7 @@ class WalletStateManager:
1309
1314
  )
1310
1315
  alt_did_puzzle_empty_recovery = DID_INNERPUZ_MOD.curry(
1311
1316
  our_inner_puzzle,
1312
- NIL,
1317
+ Program.NIL,
1313
1318
  uint64(0),
1314
1319
  parent_data.singleton_struct,
1315
1320
  parent_data.metadata,
@@ -1367,12 +1372,12 @@ class WalletStateManager:
1367
1372
  )
1368
1373
  return None
1369
1374
 
1370
- async def get_minter_did(self, launcher_coin: Coin, peer: WSChiaConnection) -> Optional[bytes32]:
1375
+ async def get_minter_did(self, launcher_coin: Coin, peer: WSChiaConnection) -> bytes32 | None:
1371
1376
  # Get minter DID
1372
1377
  eve_coin = (await self.wallet_node.fetch_children(launcher_coin.name(), peer=peer))[0]
1373
1378
  eve_coin_spend = await fetch_coin_spend_for_coin_state(eve_coin, peer)
1374
1379
  eve_full_puzzle: Program = Program.from_bytes(bytes(eve_coin_spend.puzzle_reveal))
1375
- eve_uncurried_nft: Optional[UncurriedNFT] = UncurriedNFT.uncurry(*eve_full_puzzle.uncurry())
1380
+ eve_uncurried_nft: UncurriedNFT | None = UncurriedNFT.uncurry(*eve_full_puzzle.uncurry())
1376
1381
  if eve_uncurried_nft is None:
1377
1382
  raise ValueError("Couldn't get minter DID for NFT")
1378
1383
  if not eve_uncurried_nft.supports_did:
@@ -1410,7 +1415,7 @@ class WalletStateManager:
1410
1415
  async def handle_nft(
1411
1416
  self,
1412
1417
  nft_data: NFTCoinData,
1413
- ) -> Optional[WalletIdentifier]:
1418
+ ) -> WalletIdentifier | None:
1414
1419
  """
1415
1420
  Handle the new coin when it is a NFT
1416
1421
  :param nft_data: all necessary data to process a NFT coin
@@ -1418,7 +1423,7 @@ class WalletStateManager:
1418
1423
  """
1419
1424
  wallet_identifier = None
1420
1425
  # DID ID determines which NFT wallet should process the NFT
1421
- new_did_id: Optional[bytes32] = None
1426
+ new_did_id: bytes32 | None = None
1422
1427
  old_did_id = None
1423
1428
  # P2 puzzle hash determines if we should ignore the NFT
1424
1429
  uncurried_nft: UncurriedNFT = nft_data.uncurried_nft
@@ -1446,12 +1451,12 @@ class WalletStateManager:
1446
1451
  old_p2_puzhash,
1447
1452
  new_p2_puzhash,
1448
1453
  )
1449
- new_derivation_record: Optional[
1450
- DerivationRecord
1451
- ] = await self.puzzle_store.get_derivation_record_for_puzzle_hash(new_p2_puzhash)
1452
- old_derivation_record: Optional[
1453
- DerivationRecord
1454
- ] = await self.puzzle_store.get_derivation_record_for_puzzle_hash(old_p2_puzhash)
1454
+ new_derivation_record: DerivationRecord | None = await self.puzzle_store.get_derivation_record_for_puzzle_hash(
1455
+ new_p2_puzhash
1456
+ )
1457
+ old_derivation_record: DerivationRecord | None = await self.puzzle_store.get_derivation_record_for_puzzle_hash(
1458
+ old_p2_puzhash
1459
+ )
1455
1460
  if new_derivation_record is None and old_derivation_record is None:
1456
1461
  self.log.debug(
1457
1462
  "Cannot find a P2 puzzle hash for NFT:%s, this NFT belongs to others.",
@@ -1511,7 +1516,7 @@ class WalletStateManager:
1511
1516
  coin_state: CoinState,
1512
1517
  coin_spend: CoinSpend,
1513
1518
  peer: WSChiaConnection,
1514
- ) -> Optional[WalletIdentifier]:
1519
+ ) -> WalletIdentifier | None:
1515
1520
  """
1516
1521
  Handle Clawback coins
1517
1522
  :param metadata: Clawback metadata for spending the merkle coin
@@ -1522,11 +1527,11 @@ class WalletStateManager:
1522
1527
  """
1523
1528
  # Record metadata
1524
1529
  assert coin_state.created_height is not None
1525
- is_recipient: Optional[bool] = None
1530
+ is_recipient: bool | None = None
1526
1531
  # Check if the wallet is the sender
1527
- sender_derivation_record: Optional[
1528
- DerivationRecord
1529
- ] = await self.puzzle_store.get_derivation_record_for_puzzle_hash(metadata.sender_puzzle_hash)
1532
+ sender_derivation_record: (
1533
+ DerivationRecord | None
1534
+ ) = await self.puzzle_store.get_derivation_record_for_puzzle_hash(metadata.sender_puzzle_hash)
1530
1535
  # Check if the wallet is the recipient
1531
1536
  recipient_derivation_record = await self.puzzle_store.get_derivation_record_for_puzzle_hash(
1532
1537
  metadata.recipient_puzzle_hash
@@ -1623,9 +1628,9 @@ class WalletStateManager:
1623
1628
  await self.tx_store.add_transaction_record(tx_record)
1624
1629
  return None
1625
1630
 
1626
- async def handle_vc(self, vc: VerifiedCredential) -> Optional[WalletIdentifier]:
1631
+ async def handle_vc(self, vc: VerifiedCredential) -> WalletIdentifier | None:
1627
1632
  # Check the ownership
1628
- derivation_record: Optional[DerivationRecord] = await self.puzzle_store.get_derivation_record_for_puzzle_hash(
1633
+ derivation_record: DerivationRecord | None = await self.puzzle_store.get_derivation_record_for_puzzle_hash(
1629
1634
  vc.inner_puzzle_hash
1630
1635
  )
1631
1636
  if derivation_record is None:
@@ -1644,7 +1649,7 @@ class WalletStateManager:
1644
1649
  self,
1645
1650
  coin_states: list[CoinState],
1646
1651
  peer: WSChiaConnection,
1647
- fork_height: Optional[uint32],
1652
+ fork_height: uint32 | None,
1648
1653
  ) -> None:
1649
1654
  # TODO: add comment about what this method does
1650
1655
  # Input states should already be sorted by cs_height, with reorgs at the beginning
@@ -1676,7 +1681,7 @@ class WalletStateManager:
1676
1681
  await self.retry_store.remove_state(coin_state)
1677
1682
 
1678
1683
  wallet_identifier = await self.get_wallet_identifier_for_puzzle_hash(coin_state.coin.puzzle_hash)
1679
- coin_data: Optional[Streamable] = None
1684
+ coin_data: Streamable | None = None
1680
1685
  # If we already have this coin, & it was spent & confirmed at the same heights, then return (done)
1681
1686
  if local_record is not None:
1682
1687
  local_spent = None
@@ -1781,7 +1786,7 @@ class WalletStateManager:
1781
1786
  )
1782
1787
  await self.coin_store.add_coin_record(record)
1783
1788
  # Coin first received
1784
- parent_coin_record: Optional[WalletCoinRecord] = await self.coin_store.get_coin_record(
1789
+ parent_coin_record: WalletCoinRecord | None = await self.coin_store.get_coin_record(
1785
1790
  coin_state.coin.parent_coin_info
1786
1791
  )
1787
1792
  if (
@@ -1826,8 +1831,8 @@ class WalletStateManager:
1826
1831
  fee = 0
1827
1832
 
1828
1833
  to_puzzle_hash = None
1829
- coin_spend: Optional[CoinSpend] = None
1830
- clawback_metadata: Optional[ClawbackMetadata] = None
1834
+ coin_spend: CoinSpend | None = None
1835
+ clawback_metadata: ClawbackMetadata | None = None
1831
1836
  # Find coin that doesn't belong to us
1832
1837
  amount = 0
1833
1838
  for coin in additions:
@@ -2072,7 +2077,7 @@ class WalletStateManager:
2072
2077
  self,
2073
2078
  coin_states: list[CoinState],
2074
2079
  peer: WSChiaConnection,
2075
- fork_height: Optional[uint32],
2080
+ fork_height: uint32 | None,
2076
2081
  ) -> bool:
2077
2082
  try:
2078
2083
  await self._add_coin_states(coin_states, peer, fork_height)
@@ -2122,7 +2127,7 @@ class WalletStateManager:
2122
2127
  return True
2123
2128
  return False
2124
2129
 
2125
- async def get_wallet_identifier_for_puzzle_hash(self, puzzle_hash: bytes32) -> Optional[WalletIdentifier]:
2130
+ async def get_wallet_identifier_for_puzzle_hash(self, puzzle_hash: bytes32) -> WalletIdentifier | None:
2126
2131
  wallet_identifier = await self.puzzle_store.get_wallet_identifier_for_puzzle_hash(puzzle_hash)
2127
2132
  if wallet_identifier is not None:
2128
2133
  return wallet_identifier
@@ -2138,7 +2143,7 @@ class WalletStateManager:
2138
2143
 
2139
2144
  async def get_wallet_identifier_for_coin(
2140
2145
  self, coin: Coin, hint_dict: dict[bytes32, bytes32] = {}
2141
- ) -> Optional[WalletIdentifier]:
2146
+ ) -> WalletIdentifier | None:
2142
2147
  wallet_identifier = await self.puzzle_store.get_wallet_identifier_for_puzzle_hash(coin.puzzle_hash)
2143
2148
  if (
2144
2149
  wallet_identifier is None
@@ -2153,7 +2158,7 @@ class WalletStateManager:
2153
2158
 
2154
2159
  return wallet_identifier
2155
2160
 
2156
- async def get_wallet_identifier_for_hinted_coin(self, coin: Coin, hint: bytes32) -> Optional[WalletIdentifier]:
2161
+ async def get_wallet_identifier_for_hinted_coin(self, coin: Coin, hint: bytes32) -> WalletIdentifier | None:
2157
2162
  for wallet in self.wallets.values():
2158
2163
  if await wallet.match_hinted_coin(coin, hint):
2159
2164
  return WalletIdentifier(wallet.id(), wallet.type())
@@ -2168,7 +2173,7 @@ class WalletStateManager:
2168
2173
  wallet_type: WalletType,
2169
2174
  peer: WSChiaConnection,
2170
2175
  coin_name: bytes32,
2171
- coin_data: Optional[Streamable],
2176
+ coin_data: object | None,
2172
2177
  ) -> None:
2173
2178
  """
2174
2179
  Adding coin to DB
@@ -2198,7 +2203,7 @@ class WalletStateManager:
2198
2203
  coin_confirmed_transaction = True
2199
2204
  break
2200
2205
 
2201
- parent_coin_record: Optional[WalletCoinRecord] = await self.coin_store.get_coin_record(coin.parent_coin_info)
2206
+ parent_coin_record: WalletCoinRecord | None = await self.coin_store.get_coin_record(coin.parent_coin_info)
2202
2207
  change = parent_coin_record is not None and wallet_type.value == parent_coin_record.wallet_type
2203
2208
  # If the coin is from a Clawback spent, we want to add the INCOMING_TX,
2204
2209
  # no matter if there is another TX updated.
@@ -2246,9 +2251,9 @@ class WalletStateManager:
2246
2251
  tx_records: list[TransactionRecord],
2247
2252
  push: bool = True,
2248
2253
  merge_spends: bool = True,
2249
- sign: Optional[bool] = None,
2250
- additional_signing_responses: Optional[list[SigningResponse]] = None,
2251
- extra_spends: Optional[list[WalletSpendBundle]] = None,
2254
+ sign: bool | None = None,
2255
+ additional_signing_responses: list[SigningResponse] | None = None,
2256
+ extra_spends: list[WalletSpendBundle] | None = None,
2252
2257
  singleton_records: list[SingletonRecord] = [],
2253
2258
  ) -> list[TransactionRecord]:
2254
2259
  """
@@ -2321,7 +2326,7 @@ class WalletStateManager:
2321
2326
  spendbundle_id: bytes32,
2322
2327
  name: str,
2323
2328
  send_status: MempoolInclusionStatus,
2324
- error: Optional[Err],
2329
+ error: Err | None,
2325
2330
  ) -> None:
2326
2331
  """
2327
2332
  Full node received our transaction, no need to keep it in queue anymore, unless there was an error
@@ -2329,7 +2334,7 @@ class WalletStateManager:
2329
2334
 
2330
2335
  updated = await self.tx_store.increment_sent(spendbundle_id, name, send_status, error)
2331
2336
  if updated:
2332
- tx: Optional[TransactionRecord] = await self.get_transaction(spendbundle_id)
2337
+ tx: TransactionRecord | None = await self.get_transaction(spendbundle_id)
2333
2338
  if tx is not None and tx.spend_bundle is not None:
2334
2339
  self.log.info("Checking if we need to cancel trade for tx: %s", tx.name)
2335
2340
  # we're only interested in errors that are not temporary
@@ -2385,7 +2390,7 @@ class WalletStateManager:
2385
2390
  records = await self.tx_store.get_all_transactions_for_wallet(wallet_id)
2386
2391
  return records
2387
2392
 
2388
- async def get_transaction(self, tx_id: bytes32) -> Optional[TransactionRecord]:
2393
+ async def get_transaction(self, tx_id: bytes32) -> TransactionRecord | None:
2389
2394
  return await self.tx_store.get_transaction_record(tx_id)
2390
2395
 
2391
2396
  async def get_coin_record_by_wallet_record(self, wr: WalletCoinRecord) -> CoinRecord:
@@ -2396,7 +2401,7 @@ class WalletStateManager:
2396
2401
  result = await self.coin_store.get_coin_records(**kwargs)
2397
2402
  return [await self.get_coin_record_by_wallet_record(record) for record in result.records]
2398
2403
 
2399
- async def get_wallet_for_coin(self, coin_id: bytes32) -> Optional[WalletProtocol[Any]]:
2404
+ async def get_wallet_for_coin(self, coin_id: bytes32) -> WalletProtocol[Any] | None:
2400
2405
  coin_record = await self.coin_store.get_coin_record(coin_id)
2401
2406
  if coin_record is None:
2402
2407
  return None
@@ -2448,10 +2453,10 @@ class WalletStateManager:
2448
2453
  def unlink_db(self) -> None:
2449
2454
  Path(self.db_path).unlink()
2450
2455
 
2451
- async def get_all_wallet_info_entries(self, wallet_type: Optional[WalletType] = None) -> list[WalletInfo]:
2456
+ async def get_all_wallet_info_entries(self, wallet_type: WalletType | None = None) -> list[WalletInfo]:
2452
2457
  return await self.user_store.get_all_wallet_info_entries(wallet_type)
2453
2458
 
2454
- async def get_wallet_for_asset_id(self, asset_id: str) -> Optional[WalletProtocol[Any]]:
2459
+ async def get_wallet_for_asset_id(self, asset_id: bytes32) -> WalletProtocol[Any] | None:
2455
2460
  for wallet_id, wallet in self.wallets.items():
2456
2461
  if wallet.type() in {WalletType.CAT, WalletType.CRCAT, WalletType.RCAT}:
2457
2462
  assert isinstance(wallet, CATWallet)
@@ -2459,16 +2464,16 @@ class WalletStateManager:
2459
2464
  return wallet
2460
2465
  elif wallet.type() == WalletType.DATA_LAYER:
2461
2466
  assert isinstance(wallet, DataLayerWallet)
2462
- if await wallet.get_latest_singleton(bytes32.from_hexstr(asset_id)) is not None:
2467
+ if await wallet.get_latest_singleton(asset_id) is not None:
2463
2468
  return wallet
2464
2469
  elif wallet.type() == WalletType.NFT:
2465
2470
  assert isinstance(wallet, NFTWallet)
2466
- nft_coin = await self.nft_store.get_nft_by_id(bytes32.from_hexstr(asset_id), wallet_id)
2471
+ nft_coin = await self.nft_store.get_nft_by_id(asset_id, wallet_id)
2467
2472
  if nft_coin:
2468
2473
  return wallet
2469
2474
  return None
2470
2475
 
2471
- async def get_wallet_for_puzzle_info(self, puzzle_driver: PuzzleInfo) -> Optional[WalletProtocol[Any]]:
2476
+ async def get_wallet_for_puzzle_info(self, puzzle_driver: PuzzleInfo) -> WalletProtocol[Any] | None:
2472
2477
  for wallet in self.wallets.values():
2473
2478
  match_function = getattr(wallet, "match_puzzle_info", None)
2474
2479
  if match_function is not None and callable(match_function):
@@ -2476,7 +2481,7 @@ class WalletStateManager:
2476
2481
  return wallet
2477
2482
  return None
2478
2483
 
2479
- async def create_wallet_for_puzzle_info(self, puzzle_driver: PuzzleInfo, name: Optional[str] = None) -> None:
2484
+ async def create_wallet_for_puzzle_info(self, puzzle_driver: PuzzleInfo, name: str | None = None) -> None:
2480
2485
  if AssetType(puzzle_driver.type()) in self.asset_to_wallet_map:
2481
2486
  await self.asset_to_wallet_map[AssetType(puzzle_driver.type())].create_from_puzzle_info(
2482
2487
  self,
@@ -2495,10 +2500,29 @@ class WalletStateManager:
2495
2500
  await result.commit(self)
2496
2501
  self.state_changed("wallet_created")
2497
2502
 
2503
+ async def unconfirmed_additions_or_removals_for_wallet(
2504
+ self, *, wallet_id: uint32, get: Literal["additions", "removals"]
2505
+ ) -> set[Coin]:
2506
+ unconfirmed_tx: list[TransactionRecord] = await self.tx_store.get_unconfirmed_for_wallet(wallet_id)
2507
+ return_set: set[Coin] = set()
2508
+ for tx in unconfirmed_tx:
2509
+ hint_dict = tx.hint_dict()
2510
+ checked_set = tx.removals if get == "removals" else tx.additions
2511
+ for coin in checked_set:
2512
+ if await self.does_coin_belong_to_wallet(coin, wallet_id, hint_dict):
2513
+ return_set.add(coin)
2514
+
2515
+ return return_set
2516
+
2498
2517
  async def get_spendable_coins_for_wallet(
2499
- self, wallet_id: int, records: Optional[set[WalletCoinRecord]] = None
2518
+ self,
2519
+ wallet_id: int,
2520
+ records: set[WalletCoinRecord] | None = None,
2521
+ pending_removals: set[bytes32] | None = None,
2522
+ in_one_block: bool = False,
2500
2523
  ) -> set[WalletCoinRecord]:
2501
- wallet_type = self.wallets[uint32(wallet_id)].type()
2524
+ wallet = self.wallets[uint32(wallet_id)]
2525
+ wallet_type = wallet.type()
2502
2526
  if records is None:
2503
2527
  if wallet_type == WalletType.CRCAT:
2504
2528
  records = await self.coin_store.get_unspent_coins_for_wallet(wallet_id, CoinType.CRCAT)
@@ -2506,25 +2530,30 @@ class WalletStateManager:
2506
2530
  records = await self.coin_store.get_unspent_coins_for_wallet(wallet_id)
2507
2531
 
2508
2532
  # Coins that are currently part of a transaction
2509
- unconfirmed_tx: list[TransactionRecord] = await self.tx_store.get_unconfirmed_for_wallet(wallet_id)
2510
- removal_dict: dict[bytes32, Coin] = {}
2511
- for tx in unconfirmed_tx:
2512
- for coin in tx.removals:
2513
- # TODO, "if" might not be necessary once unconfirmed tx doesn't contain coins for other wallets
2514
- if await self.does_coin_belong_to_wallet(coin, wallet_id, tx.hint_dict()):
2515
- removal_dict[coin.name()] = coin
2533
+ if pending_removals is None:
2534
+ pending_removals = {
2535
+ coin.name()
2536
+ for coin in await self.unconfirmed_additions_or_removals_for_wallet(
2537
+ wallet_id=uint32(wallet_id), get="removals"
2538
+ )
2539
+ }
2516
2540
 
2517
2541
  # Coins that are part of the trade
2518
2542
  offer_locked_coins: dict[bytes32, WalletCoinRecord] = await self.trade_manager.get_locked_coins()
2519
2543
 
2520
2544
  filtered = set()
2521
2545
  for record in records:
2522
- if record.coin.name() in offer_locked_coins:
2546
+ if record.coin.name() in {*offer_locked_coins.keys(), *pending_removals}:
2523
2547
  continue
2524
- if record.coin.name() in removal_dict:
2548
+ if hasattr(wallet, "is_coin_spendable") and not await wallet.is_coin_spendable(record):
2525
2549
  continue
2526
2550
  filtered.add(record)
2527
2551
 
2552
+ if hasattr(wallet, "max_send_quantity") and in_one_block:
2553
+ filtered_as_list = list(filtered)
2554
+ filtered_as_list.sort(reverse=True, key=lambda rec: rec.coin.amount)
2555
+ return set(filtered_as_list[0 : min(len(filtered_as_list), wallet.max_send_quantity)])
2556
+
2528
2557
  return filtered
2529
2558
 
2530
2559
  async def new_peak(self, height: uint32) -> None:
@@ -2601,10 +2630,10 @@ class WalletStateManager:
2601
2630
 
2602
2631
  return vc_wallet
2603
2632
 
2604
- async def sum_hint_for_pubkey(self, pk: bytes) -> Optional[SumHint]:
2633
+ async def sum_hint_for_pubkey(self, pk: bytes) -> SumHint | None:
2605
2634
  return await self.main_wallet.sum_hint_for_pubkey(pk)
2606
2635
 
2607
- async def path_hint_for_pubkey(self, pk: bytes) -> Optional[PathHint]:
2636
+ async def path_hint_for_pubkey(self, pk: bytes) -> PathHint | None:
2608
2637
  return await self.main_wallet.path_hint_for_pubkey(pk)
2609
2638
 
2610
2639
  async def key_hints_for_pubkeys(self, pks: list[bytes]) -> KeyHints:
@@ -2757,10 +2786,10 @@ class WalletStateManager:
2757
2786
  tx_config: TXConfig,
2758
2787
  push: bool = False,
2759
2788
  merge_spends: bool = True,
2760
- sign: Optional[bool] = None,
2789
+ sign: bool | None = None,
2761
2790
  additional_signing_responses: list[SigningResponse] = [],
2762
2791
  extra_spends: list[WalletSpendBundle] = [],
2763
- puzzle_for_pk: Optional[Callable[[G1Element], Program]] = None,
2792
+ puzzle_for_pk: Callable[[G1Element], Program] | None = None,
2764
2793
  ) -> AsyncIterator[WalletActionScope]:
2765
2794
  async with new_wallet_action_scope(
2766
2795
  self,
@@ -2780,3 +2809,200 @@ class WalletStateManager:
2780
2809
 
2781
2810
  def encode_puzzle_hash(self, puzzle_hash: bytes32) -> str:
2782
2811
  return encode_puzzle_hash(puzzle_hash, AddressType.XCH.hrp(self.config))
2812
+
2813
+ def new_outgoing_transaction(
2814
+ self,
2815
+ *,
2816
+ wallet_id: uint32,
2817
+ puzzle_hash: bytes32,
2818
+ amount: uint64,
2819
+ fee: uint64,
2820
+ spend_bundle: WalletSpendBundle,
2821
+ additions: list[Coin],
2822
+ removals: list[Coin],
2823
+ name: bytes32,
2824
+ extra_conditions: tuple[Condition, ...] = tuple(),
2825
+ trade_id: bytes32 | None = None,
2826
+ ) -> TransactionRecord:
2827
+ return TransactionRecord(
2828
+ confirmed_at_height=uint32(0),
2829
+ created_at_time=uint64(time.time()),
2830
+ to_puzzle_hash=puzzle_hash,
2831
+ to_address=self.encode_puzzle_hash(puzzle_hash),
2832
+ amount=amount,
2833
+ fee_amount=fee,
2834
+ confirmed=False,
2835
+ sent=uint32(0),
2836
+ spend_bundle=spend_bundle,
2837
+ additions=additions,
2838
+ removals=removals,
2839
+ wallet_id=wallet_id,
2840
+ sent_to=[],
2841
+ trade_id=trade_id,
2842
+ type=uint32(TransactionType.OUTGOING_TX.value),
2843
+ name=name,
2844
+ memos=compute_memos(spend_bundle),
2845
+ valid_times=parse_timelock_info(extra_conditions),
2846
+ )
2847
+
2848
+ async def split_coins(
2849
+ self,
2850
+ *,
2851
+ action_scope: WalletActionScope,
2852
+ wallet_id: uint32,
2853
+ target_coin_id: bytes32,
2854
+ amount_per_coin: uint64,
2855
+ number_of_coins: uint16,
2856
+ fee: uint64,
2857
+ extra_conditions: tuple[Condition, ...] = tuple(),
2858
+ ) -> None:
2859
+ optional_coin = await self.coin_store.get_coin_record(target_coin_id)
2860
+ if optional_coin is None:
2861
+ raise ValueError(f"Could not find coin with ID {target_coin_id}")
2862
+ else:
2863
+ coin = optional_coin.coin
2864
+
2865
+ total_amount = amount_per_coin * number_of_coins
2866
+
2867
+ if coin.amount < total_amount:
2868
+ raise ValueError(f"Coin amount: {coin.amount} is less than the total amount of the split: {total_amount}.")
2869
+
2870
+ if wallet_id not in self.wallets:
2871
+ raise ValueError(f"Wallet with ID {wallet_id} does not exist")
2872
+ wallet = self.wallets[wallet_id]
2873
+ if not isinstance(wallet, (Wallet, CATWallet)):
2874
+ raise ValueError("Cannot split coins from non-fungible wallet types")
2875
+
2876
+ outputs = [
2877
+ CreateCoin(
2878
+ await action_scope.get_puzzle_hash(self, override_reuse_puzhash_with=False),
2879
+ amount_per_coin,
2880
+ )
2881
+ for _ in range(number_of_coins)
2882
+ ]
2883
+
2884
+ if wallet.type() == WalletType.STANDARD_WALLET and coin.amount < total_amount + fee:
2885
+ async with action_scope.use() as interface:
2886
+ interface.side_effects.selected_coins.append(coin)
2887
+ coins = await wallet.select_coins(
2888
+ uint64(total_amount + fee - coin.amount),
2889
+ action_scope,
2890
+ )
2891
+ coins.add(coin)
2892
+ else:
2893
+ coins = {coin}
2894
+
2895
+ await wallet.generate_signed_transaction(
2896
+ [output.amount for output in outputs],
2897
+ [output.puzzle_hash for output in outputs],
2898
+ action_scope,
2899
+ fee,
2900
+ coins=coins,
2901
+ extra_conditions=extra_conditions,
2902
+ )
2903
+
2904
+ async def combine_coins(
2905
+ self,
2906
+ *,
2907
+ action_scope: WalletActionScope,
2908
+ wallet_id: uint32,
2909
+ number_of_coins: uint16,
2910
+ largest_first: bool,
2911
+ coin_num_limit: uint16,
2912
+ fee: uint64,
2913
+ target_coin_amount: uint64 | None = None,
2914
+ target_coin_ids: list[bytes32] | None = None,
2915
+ extra_conditions: tuple[Condition, ...] = tuple(),
2916
+ ) -> None:
2917
+ if wallet_id not in self.wallets:
2918
+ raise ValueError(f"Wallet with ID {wallet_id} does not exist")
2919
+ wallet = self.wallets[wallet_id]
2920
+ if not isinstance(wallet, (Wallet, CATWallet)):
2921
+ raise ValueError("Cannot combine coins from non-fungible wallet types")
2922
+
2923
+ coins: list[Coin] = []
2924
+
2925
+ # First get the coin IDs specified
2926
+ if target_coin_ids is not None:
2927
+ coins.extend(
2928
+ cr.coin
2929
+ for cr in (
2930
+ await self.coin_store.get_coin_records(
2931
+ wallet_id=wallet_id,
2932
+ coin_id_filter=HashFilter(target_coin_ids, mode=uint8(FilterMode.include.value)),
2933
+ )
2934
+ ).records
2935
+ )
2936
+
2937
+ async with action_scope.use() as interface:
2938
+ interface.side_effects.selected_coins.extend(coins)
2939
+
2940
+ # Next let's select enough coins to meet the target + fee if there is one
2941
+ fungible_amount_needed = uint64(0) if target_coin_amount is None else target_coin_amount
2942
+ if isinstance(wallet, Wallet):
2943
+ fungible_amount_needed = uint64(fungible_amount_needed + fee)
2944
+ amount_selected = sum(c.amount for c in coins)
2945
+ if amount_selected < fungible_amount_needed: # implicit fungible_amount_needed > 0 here
2946
+ coins.extend(
2947
+ await wallet.select_coins(
2948
+ amount=uint64(fungible_amount_needed - amount_selected), action_scope=action_scope
2949
+ )
2950
+ )
2951
+
2952
+ if len(coins) > number_of_coins:
2953
+ raise ValueError(
2954
+ f"Options specified cannot be met without selecting more coins than specified: {len(coins)}"
2955
+ )
2956
+
2957
+ # Now let's select enough coins to get to the target number to combine
2958
+ if len(coins) < number_of_coins:
2959
+ async with action_scope.use() as interface:
2960
+ coins.extend(
2961
+ cr.coin
2962
+ for cr in (
2963
+ await self.coin_store.get_coin_records(
2964
+ wallet_id=wallet_id,
2965
+ limit=uint32(number_of_coins - len(coins)),
2966
+ order=CoinRecordOrder.amount,
2967
+ coin_id_filter=HashFilter(
2968
+ [c.name() for c in interface.side_effects.selected_coins],
2969
+ mode=uint8(FilterMode.exclude.value),
2970
+ ),
2971
+ reverse=largest_first,
2972
+ )
2973
+ ).records
2974
+ )
2975
+
2976
+ async with action_scope.use() as interface:
2977
+ interface.side_effects.selected_coins.extend(coins)
2978
+
2979
+ primary_output_amount = (
2980
+ uint64(sum(c.amount for c in coins)) if target_coin_amount is None else target_coin_amount
2981
+ )
2982
+ if isinstance(wallet, Wallet):
2983
+ primary_output_amount = uint64(primary_output_amount - fee)
2984
+
2985
+ await wallet.generate_signed_transaction(
2986
+ [primary_output_amount],
2987
+ [await action_scope.get_puzzle_hash(self)],
2988
+ action_scope,
2989
+ fee,
2990
+ coins=set(coins),
2991
+ extra_conditions=extra_conditions,
2992
+ )
2993
+
2994
+ def new_pool_wallet_pubkey(self) -> G1Element:
2995
+ # We assign a pseudo unique id to each pool wallet, so that each one gets its own deterministic
2996
+ # owner and auth keys. The public keys will go on the blockchain, and the private keys can be found
2997
+ # using the root SK and trying each index from zero. The indexes are not fully unique though,
2998
+ # because the PoolWallet is not created until the tx gets confirmed on chain. Therefore if we
2999
+ # make multiple pool wallets at the same time, they will have the same ID.
3000
+ max_pwi = 1
3001
+ for _, wallet in self.wallets.items():
3002
+ if wallet.type() == WalletType.POOLING_WALLET:
3003
+ max_pwi += 1
3004
+
3005
+ if max_pwi + 1 >= (MAX_POOL_WALLETS - 1):
3006
+ raise ValueError(f"Too many pool wallets ({max_pwi}), cannot create any more on this key.")
3007
+
3008
+ return master_sk_to_singleton_owner_sk(self.get_master_private_key(), uint32(max_pwi)).get_g1()