chia-blockchain 2.5.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1042) hide show
  1. chia/__init__.py +10 -0
  2. chia/__main__.py +5 -0
  3. chia/_tests/README.md +53 -0
  4. chia/_tests/__init__.py +0 -0
  5. chia/_tests/blockchain/__init__.py +0 -0
  6. chia/_tests/blockchain/blockchain_test_utils.py +195 -0
  7. chia/_tests/blockchain/config.py +4 -0
  8. chia/_tests/blockchain/test_augmented_chain.py +145 -0
  9. chia/_tests/blockchain/test_blockchain.py +4202 -0
  10. chia/_tests/blockchain/test_blockchain_transactions.py +1031 -0
  11. chia/_tests/blockchain/test_build_chains.py +59 -0
  12. chia/_tests/blockchain/test_get_block_generator.py +72 -0
  13. chia/_tests/blockchain/test_lookup_fork_chain.py +194 -0
  14. chia/_tests/build-init-files.py +92 -0
  15. chia/_tests/build-job-matrix.py +204 -0
  16. chia/_tests/check_pytest_monitor_output.py +34 -0
  17. chia/_tests/check_sql_statements.py +72 -0
  18. chia/_tests/chia-start-sim +42 -0
  19. chia/_tests/clvm/__init__.py +0 -0
  20. chia/_tests/clvm/benchmark_costs.py +23 -0
  21. chia/_tests/clvm/coin_store.py +149 -0
  22. chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
  23. chia/_tests/clvm/test_clvm_step.py +37 -0
  24. chia/_tests/clvm/test_condition_codes.py +13 -0
  25. chia/_tests/clvm/test_curry_and_treehash.py +55 -0
  26. chia/_tests/clvm/test_message_conditions.py +184 -0
  27. chia/_tests/clvm/test_program.py +150 -0
  28. chia/_tests/clvm/test_puzzle_compression.py +143 -0
  29. chia/_tests/clvm/test_puzzle_drivers.py +45 -0
  30. chia/_tests/clvm/test_puzzles.py +242 -0
  31. chia/_tests/clvm/test_singletons.py +540 -0
  32. chia/_tests/clvm/test_spend_sim.py +181 -0
  33. chia/_tests/cmds/__init__.py +0 -0
  34. chia/_tests/cmds/cmd_test_utils.py +469 -0
  35. chia/_tests/cmds/config.py +3 -0
  36. chia/_tests/cmds/conftest.py +23 -0
  37. chia/_tests/cmds/test_click_types.py +200 -0
  38. chia/_tests/cmds/test_cmd_framework.py +620 -0
  39. chia/_tests/cmds/test_cmds_util.py +97 -0
  40. chia/_tests/cmds/test_daemon.py +92 -0
  41. chia/_tests/cmds/test_dev_gh.py +131 -0
  42. chia/_tests/cmds/test_farm_cmd.py +66 -0
  43. chia/_tests/cmds/test_show.py +116 -0
  44. chia/_tests/cmds/test_sim.py +207 -0
  45. chia/_tests/cmds/test_timelock_args.py +75 -0
  46. chia/_tests/cmds/test_tx_config_args.py +154 -0
  47. chia/_tests/cmds/testing_classes.py +59 -0
  48. chia/_tests/cmds/wallet/__init__.py +0 -0
  49. chia/_tests/cmds/wallet/test_consts.py +47 -0
  50. chia/_tests/cmds/wallet/test_dao.py +565 -0
  51. chia/_tests/cmds/wallet/test_did.py +403 -0
  52. chia/_tests/cmds/wallet/test_nft.py +471 -0
  53. chia/_tests/cmds/wallet/test_notifications.py +124 -0
  54. chia/_tests/cmds/wallet/test_offer.toffer +1 -0
  55. chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
  56. chia/_tests/cmds/wallet/test_vcs.py +400 -0
  57. chia/_tests/cmds/wallet/test_wallet.py +1125 -0
  58. chia/_tests/cmds/wallet/test_wallet_check.py +109 -0
  59. chia/_tests/conftest.py +1419 -0
  60. chia/_tests/connection_utils.py +125 -0
  61. chia/_tests/core/__init__.py +0 -0
  62. chia/_tests/core/cmds/__init__.py +0 -0
  63. chia/_tests/core/cmds/test_beta.py +382 -0
  64. chia/_tests/core/cmds/test_keys.py +1734 -0
  65. chia/_tests/core/cmds/test_wallet.py +126 -0
  66. chia/_tests/core/config.py +3 -0
  67. chia/_tests/core/consensus/__init__.py +0 -0
  68. chia/_tests/core/consensus/test_block_creation.py +54 -0
  69. chia/_tests/core/consensus/test_pot_iterations.py +117 -0
  70. chia/_tests/core/custom_types/__init__.py +0 -0
  71. chia/_tests/core/custom_types/test_coin.py +107 -0
  72. chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
  73. chia/_tests/core/custom_types/test_spend_bundle.py +70 -0
  74. chia/_tests/core/daemon/__init__.py +0 -0
  75. chia/_tests/core/daemon/config.py +4 -0
  76. chia/_tests/core/daemon/test_daemon.py +2128 -0
  77. chia/_tests/core/daemon/test_daemon_register.py +109 -0
  78. chia/_tests/core/daemon/test_keychain_proxy.py +101 -0
  79. chia/_tests/core/data_layer/__init__.py +0 -0
  80. chia/_tests/core/data_layer/config.py +5 -0
  81. chia/_tests/core/data_layer/conftest.py +106 -0
  82. chia/_tests/core/data_layer/test_data_cli.py +56 -0
  83. chia/_tests/core/data_layer/test_data_layer.py +83 -0
  84. chia/_tests/core/data_layer/test_data_layer_util.py +218 -0
  85. chia/_tests/core/data_layer/test_data_rpc.py +3847 -0
  86. chia/_tests/core/data_layer/test_data_store.py +2424 -0
  87. chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
  88. chia/_tests/core/data_layer/test_plugin.py +91 -0
  89. chia/_tests/core/data_layer/util.py +233 -0
  90. chia/_tests/core/farmer/__init__.py +0 -0
  91. chia/_tests/core/farmer/config.py +3 -0
  92. chia/_tests/core/farmer/test_farmer_api.py +103 -0
  93. chia/_tests/core/full_node/__init__.py +0 -0
  94. chia/_tests/core/full_node/config.py +4 -0
  95. chia/_tests/core/full_node/dos/__init__.py +0 -0
  96. chia/_tests/core/full_node/dos/config.py +3 -0
  97. chia/_tests/core/full_node/full_sync/__init__.py +0 -0
  98. chia/_tests/core/full_node/full_sync/config.py +4 -0
  99. chia/_tests/core/full_node/full_sync/test_full_sync.py +443 -0
  100. chia/_tests/core/full_node/ram_db.py +27 -0
  101. chia/_tests/core/full_node/stores/__init__.py +0 -0
  102. chia/_tests/core/full_node/stores/config.py +4 -0
  103. chia/_tests/core/full_node/stores/test_block_store.py +590 -0
  104. chia/_tests/core/full_node/stores/test_coin_store.py +897 -0
  105. chia/_tests/core/full_node/stores/test_full_node_store.py +1219 -0
  106. chia/_tests/core/full_node/stores/test_hint_store.py +229 -0
  107. chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
  108. chia/_tests/core/full_node/test_address_manager.py +588 -0
  109. chia/_tests/core/full_node/test_block_height_map.py +556 -0
  110. chia/_tests/core/full_node/test_conditions.py +556 -0
  111. chia/_tests/core/full_node/test_full_node.py +2700 -0
  112. chia/_tests/core/full_node/test_generator_tools.py +82 -0
  113. chia/_tests/core/full_node/test_hint_management.py +104 -0
  114. chia/_tests/core/full_node/test_node_load.py +34 -0
  115. chia/_tests/core/full_node/test_performance.py +179 -0
  116. chia/_tests/core/full_node/test_subscriptions.py +492 -0
  117. chia/_tests/core/full_node/test_transactions.py +203 -0
  118. chia/_tests/core/full_node/test_tx_processing_queue.py +155 -0
  119. chia/_tests/core/large_block.py +2388 -0
  120. chia/_tests/core/make_block_generator.py +70 -0
  121. chia/_tests/core/mempool/__init__.py +0 -0
  122. chia/_tests/core/mempool/config.py +4 -0
  123. chia/_tests/core/mempool/test_mempool.py +3255 -0
  124. chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
  125. chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
  126. chia/_tests/core/mempool/test_mempool_item_queries.py +190 -0
  127. chia/_tests/core/mempool/test_mempool_manager.py +2084 -0
  128. chia/_tests/core/mempool/test_mempool_performance.py +64 -0
  129. chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
  130. chia/_tests/core/node_height.py +28 -0
  131. chia/_tests/core/server/__init__.py +0 -0
  132. chia/_tests/core/server/config.py +3 -0
  133. chia/_tests/core/server/flood.py +84 -0
  134. chia/_tests/core/server/serve.py +135 -0
  135. chia/_tests/core/server/test_api_protocol.py +21 -0
  136. chia/_tests/core/server/test_capabilities.py +66 -0
  137. chia/_tests/core/server/test_dos.py +319 -0
  138. chia/_tests/core/server/test_event_loop.py +109 -0
  139. chia/_tests/core/server/test_loop.py +294 -0
  140. chia/_tests/core/server/test_node_discovery.py +73 -0
  141. chia/_tests/core/server/test_rate_limits.py +482 -0
  142. chia/_tests/core/server/test_server.py +226 -0
  143. chia/_tests/core/server/test_upnp.py +8 -0
  144. chia/_tests/core/services/__init__.py +0 -0
  145. chia/_tests/core/services/config.py +3 -0
  146. chia/_tests/core/services/test_services.py +188 -0
  147. chia/_tests/core/ssl/__init__.py +0 -0
  148. chia/_tests/core/ssl/config.py +3 -0
  149. chia/_tests/core/ssl/test_ssl.py +202 -0
  150. chia/_tests/core/test_coins.py +33 -0
  151. chia/_tests/core/test_cost_calculation.py +313 -0
  152. chia/_tests/core/test_crawler.py +175 -0
  153. chia/_tests/core/test_crawler_rpc.py +53 -0
  154. chia/_tests/core/test_daemon_rpc.py +24 -0
  155. chia/_tests/core/test_db_conversion.py +130 -0
  156. chia/_tests/core/test_db_validation.py +162 -0
  157. chia/_tests/core/test_farmer_harvester_rpc.py +505 -0
  158. chia/_tests/core/test_filter.py +35 -0
  159. chia/_tests/core/test_full_node_rpc.py +768 -0
  160. chia/_tests/core/test_merkle_set.py +343 -0
  161. chia/_tests/core/test_program.py +47 -0
  162. chia/_tests/core/test_rpc_util.py +86 -0
  163. chia/_tests/core/test_seeder.py +420 -0
  164. chia/_tests/core/test_setproctitle.py +13 -0
  165. chia/_tests/core/util/__init__.py +0 -0
  166. chia/_tests/core/util/config.py +4 -0
  167. chia/_tests/core/util/test_block_cache.py +44 -0
  168. chia/_tests/core/util/test_cached_bls.py +57 -0
  169. chia/_tests/core/util/test_config.py +337 -0
  170. chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
  171. chia/_tests/core/util/test_files.py +391 -0
  172. chia/_tests/core/util/test_jsonify.py +146 -0
  173. chia/_tests/core/util/test_keychain.py +522 -0
  174. chia/_tests/core/util/test_keyring_wrapper.py +491 -0
  175. chia/_tests/core/util/test_lockfile.py +380 -0
  176. chia/_tests/core/util/test_log_exceptions.py +187 -0
  177. chia/_tests/core/util/test_lru_cache.py +56 -0
  178. chia/_tests/core/util/test_significant_bits.py +40 -0
  179. chia/_tests/core/util/test_streamable.py +883 -0
  180. chia/_tests/db/__init__.py +0 -0
  181. chia/_tests/db/test_db_wrapper.py +566 -0
  182. chia/_tests/environments/__init__.py +0 -0
  183. chia/_tests/environments/common.py +35 -0
  184. chia/_tests/environments/full_node.py +47 -0
  185. chia/_tests/environments/wallet.py +429 -0
  186. chia/_tests/ether.py +19 -0
  187. chia/_tests/farmer_harvester/__init__.py +0 -0
  188. chia/_tests/farmer_harvester/config.py +3 -0
  189. chia/_tests/farmer_harvester/test_farmer.py +1264 -0
  190. chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
  191. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +131 -0
  192. chia/_tests/farmer_harvester/test_third_party_harvesters.py +528 -0
  193. chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
  194. chia/_tests/fee_estimation/__init__.py +0 -0
  195. chia/_tests/fee_estimation/config.py +3 -0
  196. chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
  197. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
  198. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +144 -0
  199. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
  200. chia/_tests/generator/__init__.py +0 -0
  201. chia/_tests/generator/puzzles/__init__.py +0 -0
  202. chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
  203. chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
  204. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
  205. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
  206. chia/_tests/generator/test_compression.py +201 -0
  207. chia/_tests/generator/test_generator_types.py +44 -0
  208. chia/_tests/generator/test_rom.py +180 -0
  209. chia/_tests/plot_sync/__init__.py +0 -0
  210. chia/_tests/plot_sync/config.py +3 -0
  211. chia/_tests/plot_sync/test_delta.py +101 -0
  212. chia/_tests/plot_sync/test_plot_sync.py +618 -0
  213. chia/_tests/plot_sync/test_receiver.py +451 -0
  214. chia/_tests/plot_sync/test_sender.py +116 -0
  215. chia/_tests/plot_sync/test_sync_simulated.py +451 -0
  216. chia/_tests/plot_sync/util.py +68 -0
  217. chia/_tests/plotting/__init__.py +0 -0
  218. chia/_tests/plotting/config.py +3 -0
  219. chia/_tests/plotting/test_plot_manager.py +781 -0
  220. chia/_tests/plotting/util.py +12 -0
  221. chia/_tests/pools/__init__.py +0 -0
  222. chia/_tests/pools/config.py +5 -0
  223. chia/_tests/pools/test_pool_cli_parsing.py +128 -0
  224. chia/_tests/pools/test_pool_cmdline.py +1001 -0
  225. chia/_tests/pools/test_pool_config.py +42 -0
  226. chia/_tests/pools/test_pool_puzzles_lifecycle.py +397 -0
  227. chia/_tests/pools/test_pool_rpc.py +1123 -0
  228. chia/_tests/pools/test_pool_wallet.py +205 -0
  229. chia/_tests/pools/test_wallet_pool_store.py +161 -0
  230. chia/_tests/process_junit.py +348 -0
  231. chia/_tests/rpc/__init__.py +0 -0
  232. chia/_tests/rpc/test_rpc_client.py +138 -0
  233. chia/_tests/rpc/test_rpc_server.py +183 -0
  234. chia/_tests/simulation/__init__.py +0 -0
  235. chia/_tests/simulation/config.py +6 -0
  236. chia/_tests/simulation/test_simulation.py +501 -0
  237. chia/_tests/simulation/test_simulator.py +232 -0
  238. chia/_tests/simulation/test_start_simulator.py +107 -0
  239. chia/_tests/testconfig.py +13 -0
  240. chia/_tests/timelord/__init__.py +0 -0
  241. chia/_tests/timelord/config.py +3 -0
  242. chia/_tests/timelord/test_new_peak.py +437 -0
  243. chia/_tests/timelord/test_timelord.py +11 -0
  244. chia/_tests/tools/1315537.json +170 -0
  245. chia/_tests/tools/1315544.json +160 -0
  246. chia/_tests/tools/1315630.json +150 -0
  247. chia/_tests/tools/300000.json +105 -0
  248. chia/_tests/tools/442734.json +140 -0
  249. chia/_tests/tools/466212.json +130 -0
  250. chia/_tests/tools/__init__.py +0 -0
  251. chia/_tests/tools/config.py +5 -0
  252. chia/_tests/tools/test-blockchain-db.sqlite +0 -0
  253. chia/_tests/tools/test_full_sync.py +30 -0
  254. chia/_tests/tools/test_legacy_keyring.py +82 -0
  255. chia/_tests/tools/test_run_block.py +128 -0
  256. chia/_tests/tools/test_virtual_project.py +591 -0
  257. chia/_tests/util/__init__.py +0 -0
  258. chia/_tests/util/benchmark_cost.py +170 -0
  259. chia/_tests/util/benchmarks.py +153 -0
  260. chia/_tests/util/bip39_test_vectors.json +148 -0
  261. chia/_tests/util/blockchain.py +134 -0
  262. chia/_tests/util/blockchain_mock.py +132 -0
  263. chia/_tests/util/build_network_protocol_files.py +302 -0
  264. chia/_tests/util/clvm_generator.bin +0 -0
  265. chia/_tests/util/config.py +3 -0
  266. chia/_tests/util/constants.py +20 -0
  267. chia/_tests/util/db_connection.py +37 -0
  268. chia/_tests/util/full_sync.py +253 -0
  269. chia/_tests/util/gen_ssl_certs.py +114 -0
  270. chia/_tests/util/generator_tools_testing.py +45 -0
  271. chia/_tests/util/get_name_puzzle_conditions.py +52 -0
  272. chia/_tests/util/key_tool.py +36 -0
  273. chia/_tests/util/misc.py +675 -0
  274. chia/_tests/util/network_protocol_data.py +1072 -0
  275. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  276. chia/_tests/util/protocol_messages_json.py +2701 -0
  277. chia/_tests/util/rpc.py +26 -0
  278. chia/_tests/util/run_block.py +163 -0
  279. chia/_tests/util/setup_nodes.py +481 -0
  280. chia/_tests/util/spend_sim.py +492 -0
  281. chia/_tests/util/split_managers.py +102 -0
  282. chia/_tests/util/temp_file.py +14 -0
  283. chia/_tests/util/test_action_scope.py +144 -0
  284. chia/_tests/util/test_async_pool.py +366 -0
  285. chia/_tests/util/test_build_job_matrix.py +42 -0
  286. chia/_tests/util/test_build_network_protocol_files.py +7 -0
  287. chia/_tests/util/test_chia_version.py +50 -0
  288. chia/_tests/util/test_collection.py +11 -0
  289. chia/_tests/util/test_condition_tools.py +229 -0
  290. chia/_tests/util/test_config.py +426 -0
  291. chia/_tests/util/test_dump_keyring.py +60 -0
  292. chia/_tests/util/test_errors.py +10 -0
  293. chia/_tests/util/test_full_block_utils.py +279 -0
  294. chia/_tests/util/test_installed.py +20 -0
  295. chia/_tests/util/test_limited_semaphore.py +53 -0
  296. chia/_tests/util/test_logging_filter.py +42 -0
  297. chia/_tests/util/test_misc.py +445 -0
  298. chia/_tests/util/test_network.py +73 -0
  299. chia/_tests/util/test_network_protocol_files.py +578 -0
  300. chia/_tests/util/test_network_protocol_json.py +267 -0
  301. chia/_tests/util/test_network_protocol_test.py +256 -0
  302. chia/_tests/util/test_paginator.py +71 -0
  303. chia/_tests/util/test_pprint.py +17 -0
  304. chia/_tests/util/test_priority_mutex.py +488 -0
  305. chia/_tests/util/test_recursive_replace.py +116 -0
  306. chia/_tests/util/test_replace_str_to_bytes.py +137 -0
  307. chia/_tests/util/test_service_groups.py +15 -0
  308. chia/_tests/util/test_ssl_check.py +31 -0
  309. chia/_tests/util/test_testnet_overrides.py +19 -0
  310. chia/_tests/util/test_tests_misc.py +38 -0
  311. chia/_tests/util/test_timing.py +37 -0
  312. chia/_tests/util/test_trusted_peer.py +51 -0
  313. chia/_tests/util/time_out_assert.py +191 -0
  314. chia/_tests/wallet/__init__.py +0 -0
  315. chia/_tests/wallet/cat_wallet/__init__.py +0 -0
  316. chia/_tests/wallet/cat_wallet/config.py +4 -0
  317. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
  318. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
  319. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1826 -0
  320. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
  321. chia/_tests/wallet/cat_wallet/test_trades.py +2600 -0
  322. chia/_tests/wallet/clawback/__init__.py +0 -0
  323. chia/_tests/wallet/clawback/config.py +3 -0
  324. chia/_tests/wallet/clawback/test_clawback_decorator.py +78 -0
  325. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
  326. chia/_tests/wallet/clawback/test_clawback_metadata.py +50 -0
  327. chia/_tests/wallet/config.py +4 -0
  328. chia/_tests/wallet/conftest.py +278 -0
  329. chia/_tests/wallet/dao_wallet/__init__.py +0 -0
  330. chia/_tests/wallet/dao_wallet/config.py +3 -0
  331. chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1330 -0
  332. chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
  333. chia/_tests/wallet/db_wallet/__init__.py +0 -0
  334. chia/_tests/wallet/db_wallet/config.py +3 -0
  335. chia/_tests/wallet/db_wallet/test_db_graftroot.py +141 -0
  336. chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
  337. chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
  338. chia/_tests/wallet/did_wallet/__init__.py +0 -0
  339. chia/_tests/wallet/did_wallet/config.py +4 -0
  340. chia/_tests/wallet/did_wallet/test_did.py +2284 -0
  341. chia/_tests/wallet/nft_wallet/__init__.py +0 -0
  342. chia/_tests/wallet/nft_wallet/config.py +4 -0
  343. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1493 -0
  344. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1024 -0
  345. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +375 -0
  346. chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
  347. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
  348. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2584 -0
  349. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
  350. chia/_tests/wallet/rpc/__init__.py +0 -0
  351. chia/_tests/wallet/rpc/config.py +4 -0
  352. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +285 -0
  353. chia/_tests/wallet/rpc/test_wallet_rpc.py +3153 -0
  354. chia/_tests/wallet/simple_sync/__init__.py +0 -0
  355. chia/_tests/wallet/simple_sync/config.py +3 -0
  356. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +718 -0
  357. chia/_tests/wallet/sync/__init__.py +0 -0
  358. chia/_tests/wallet/sync/config.py +4 -0
  359. chia/_tests/wallet/sync/test_wallet_sync.py +1692 -0
  360. chia/_tests/wallet/test_address_type.py +189 -0
  361. chia/_tests/wallet/test_bech32m.py +45 -0
  362. chia/_tests/wallet/test_clvm_streamable.py +244 -0
  363. chia/_tests/wallet/test_coin_management.py +354 -0
  364. chia/_tests/wallet/test_coin_selection.py +588 -0
  365. chia/_tests/wallet/test_conditions.py +400 -0
  366. chia/_tests/wallet/test_debug_spend_bundle.py +218 -0
  367. chia/_tests/wallet/test_new_wallet_protocol.py +1174 -0
  368. chia/_tests/wallet/test_nft_store.py +192 -0
  369. chia/_tests/wallet/test_notifications.py +196 -0
  370. chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
  371. chia/_tests/wallet/test_puzzle_store.py +132 -0
  372. chia/_tests/wallet/test_sign_coin_spends.py +159 -0
  373. chia/_tests/wallet/test_signer_protocol.py +947 -0
  374. chia/_tests/wallet/test_singleton.py +122 -0
  375. chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
  376. chia/_tests/wallet/test_singleton_store.py +152 -0
  377. chia/_tests/wallet/test_taproot.py +19 -0
  378. chia/_tests/wallet/test_transaction_store.py +945 -0
  379. chia/_tests/wallet/test_util.py +185 -0
  380. chia/_tests/wallet/test_wallet.py +2139 -0
  381. chia/_tests/wallet/test_wallet_action_scope.py +85 -0
  382. chia/_tests/wallet/test_wallet_blockchain.py +111 -0
  383. chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
  384. chia/_tests/wallet/test_wallet_interested_store.py +43 -0
  385. chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
  386. chia/_tests/wallet/test_wallet_node.py +780 -0
  387. chia/_tests/wallet/test_wallet_retry.py +95 -0
  388. chia/_tests/wallet/test_wallet_state_manager.py +259 -0
  389. chia/_tests/wallet/test_wallet_test_framework.py +275 -0
  390. chia/_tests/wallet/test_wallet_trade_store.py +218 -0
  391. chia/_tests/wallet/test_wallet_user_store.py +34 -0
  392. chia/_tests/wallet/test_wallet_utils.py +156 -0
  393. chia/_tests/wallet/vc_wallet/__init__.py +0 -0
  394. chia/_tests/wallet/vc_wallet/config.py +3 -0
  395. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
  396. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
  397. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +830 -0
  398. chia/_tests/wallet/wallet_block_tools.py +327 -0
  399. chia/_tests/weight_proof/__init__.py +0 -0
  400. chia/_tests/weight_proof/config.py +3 -0
  401. chia/_tests/weight_proof/test_weight_proof.py +528 -0
  402. chia/apis.py +19 -0
  403. chia/clvm/__init__.py +0 -0
  404. chia/cmds/__init__.py +0 -0
  405. chia/cmds/beta.py +184 -0
  406. chia/cmds/beta_funcs.py +137 -0
  407. chia/cmds/check_wallet_db.py +420 -0
  408. chia/cmds/chia.py +151 -0
  409. chia/cmds/cmd_classes.py +323 -0
  410. chia/cmds/cmd_helpers.py +242 -0
  411. chia/cmds/cmds_util.py +488 -0
  412. chia/cmds/coin_funcs.py +275 -0
  413. chia/cmds/coins.py +182 -0
  414. chia/cmds/completion.py +49 -0
  415. chia/cmds/configure.py +332 -0
  416. chia/cmds/dao.py +1064 -0
  417. chia/cmds/dao_funcs.py +598 -0
  418. chia/cmds/data.py +708 -0
  419. chia/cmds/data_funcs.py +385 -0
  420. chia/cmds/db.py +87 -0
  421. chia/cmds/db_backup_func.py +77 -0
  422. chia/cmds/db_upgrade_func.py +452 -0
  423. chia/cmds/db_validate_func.py +184 -0
  424. chia/cmds/dev.py +18 -0
  425. chia/cmds/farm.py +100 -0
  426. chia/cmds/farm_funcs.py +200 -0
  427. chia/cmds/gh.py +275 -0
  428. chia/cmds/init.py +63 -0
  429. chia/cmds/init_funcs.py +367 -0
  430. chia/cmds/installers.py +131 -0
  431. chia/cmds/keys.py +527 -0
  432. chia/cmds/keys_funcs.py +863 -0
  433. chia/cmds/netspace.py +50 -0
  434. chia/cmds/netspace_funcs.py +54 -0
  435. chia/cmds/options.py +32 -0
  436. chia/cmds/param_types.py +238 -0
  437. chia/cmds/passphrase.py +131 -0
  438. chia/cmds/passphrase_funcs.py +292 -0
  439. chia/cmds/peer.py +51 -0
  440. chia/cmds/peer_funcs.py +129 -0
  441. chia/cmds/plotnft.py +260 -0
  442. chia/cmds/plotnft_funcs.py +405 -0
  443. chia/cmds/plots.py +230 -0
  444. chia/cmds/plotters.py +18 -0
  445. chia/cmds/rpc.py +208 -0
  446. chia/cmds/show.py +72 -0
  447. chia/cmds/show_funcs.py +215 -0
  448. chia/cmds/signer.py +296 -0
  449. chia/cmds/sim.py +225 -0
  450. chia/cmds/sim_funcs.py +509 -0
  451. chia/cmds/start.py +24 -0
  452. chia/cmds/start_funcs.py +109 -0
  453. chia/cmds/stop.py +62 -0
  454. chia/cmds/units.py +9 -0
  455. chia/cmds/wallet.py +1901 -0
  456. chia/cmds/wallet_funcs.py +1874 -0
  457. chia/consensus/__init__.py +0 -0
  458. chia/consensus/block_body_validation.py +562 -0
  459. chia/consensus/block_creation.py +546 -0
  460. chia/consensus/block_header_validation.py +1059 -0
  461. chia/consensus/block_record.py +31 -0
  462. chia/consensus/block_rewards.py +53 -0
  463. chia/consensus/blockchain.py +1087 -0
  464. chia/consensus/blockchain_interface.py +56 -0
  465. chia/consensus/coinbase.py +30 -0
  466. chia/consensus/condition_costs.py +9 -0
  467. chia/consensus/constants.py +49 -0
  468. chia/consensus/cost_calculator.py +15 -0
  469. chia/consensus/default_constants.py +89 -0
  470. chia/consensus/deficit.py +55 -0
  471. chia/consensus/difficulty_adjustment.py +412 -0
  472. chia/consensus/find_fork_point.py +111 -0
  473. chia/consensus/full_block_to_block_record.py +167 -0
  474. chia/consensus/get_block_challenge.py +106 -0
  475. chia/consensus/get_block_generator.py +27 -0
  476. chia/consensus/make_sub_epoch_summary.py +210 -0
  477. chia/consensus/multiprocess_validation.py +268 -0
  478. chia/consensus/pos_quality.py +19 -0
  479. chia/consensus/pot_iterations.py +67 -0
  480. chia/consensus/puzzles/__init__.py +0 -0
  481. chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
  482. chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
  483. chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
  484. chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
  485. chia/consensus/vdf_info_computation.py +156 -0
  486. chia/daemon/__init__.py +0 -0
  487. chia/daemon/client.py +252 -0
  488. chia/daemon/keychain_proxy.py +502 -0
  489. chia/daemon/keychain_server.py +365 -0
  490. chia/daemon/server.py +1606 -0
  491. chia/daemon/windows_signal.py +56 -0
  492. chia/data_layer/__init__.py +0 -0
  493. chia/data_layer/data_layer.py +1291 -0
  494. chia/data_layer/data_layer_api.py +33 -0
  495. chia/data_layer/data_layer_errors.py +50 -0
  496. chia/data_layer/data_layer_server.py +170 -0
  497. chia/data_layer/data_layer_util.py +985 -0
  498. chia/data_layer/data_layer_wallet.py +1311 -0
  499. chia/data_layer/data_store.py +2267 -0
  500. chia/data_layer/dl_wallet_store.py +407 -0
  501. chia/data_layer/download_data.py +389 -0
  502. chia/data_layer/puzzles/__init__.py +0 -0
  503. chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
  504. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
  505. chia/data_layer/s3_plugin_config.yml +33 -0
  506. chia/data_layer/s3_plugin_service.py +468 -0
  507. chia/data_layer/util/__init__.py +0 -0
  508. chia/data_layer/util/benchmark.py +107 -0
  509. chia/data_layer/util/plugin.py +40 -0
  510. chia/farmer/__init__.py +0 -0
  511. chia/farmer/farmer.py +923 -0
  512. chia/farmer/farmer_api.py +820 -0
  513. chia/full_node/__init__.py +0 -0
  514. chia/full_node/bitcoin_fee_estimator.py +85 -0
  515. chia/full_node/block_height_map.py +271 -0
  516. chia/full_node/block_store.py +576 -0
  517. chia/full_node/bundle_tools.py +19 -0
  518. chia/full_node/coin_store.py +647 -0
  519. chia/full_node/fee_estimate.py +54 -0
  520. chia/full_node/fee_estimate_store.py +24 -0
  521. chia/full_node/fee_estimation.py +92 -0
  522. chia/full_node/fee_estimator.py +90 -0
  523. chia/full_node/fee_estimator_constants.py +38 -0
  524. chia/full_node/fee_estimator_interface.py +42 -0
  525. chia/full_node/fee_history.py +25 -0
  526. chia/full_node/fee_tracker.py +564 -0
  527. chia/full_node/full_node.py +3327 -0
  528. chia/full_node/full_node_api.py +2025 -0
  529. chia/full_node/full_node_store.py +1033 -0
  530. chia/full_node/hint_management.py +56 -0
  531. chia/full_node/hint_store.py +93 -0
  532. chia/full_node/mempool.py +589 -0
  533. chia/full_node/mempool_check_conditions.py +146 -0
  534. chia/full_node/mempool_manager.py +853 -0
  535. chia/full_node/pending_tx_cache.py +112 -0
  536. chia/full_node/puzzles/__init__.py +0 -0
  537. chia/full_node/puzzles/block_program_zero.clsp +14 -0
  538. chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
  539. chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
  540. chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
  541. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
  542. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
  543. chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
  544. chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
  545. chia/full_node/signage_point.py +16 -0
  546. chia/full_node/subscriptions.py +247 -0
  547. chia/full_node/sync_store.py +146 -0
  548. chia/full_node/tx_processing_queue.py +78 -0
  549. chia/full_node/util/__init__.py +0 -0
  550. chia/full_node/weight_proof.py +1720 -0
  551. chia/harvester/__init__.py +0 -0
  552. chia/harvester/harvester.py +272 -0
  553. chia/harvester/harvester_api.py +380 -0
  554. chia/introducer/__init__.py +0 -0
  555. chia/introducer/introducer.py +122 -0
  556. chia/introducer/introducer_api.py +70 -0
  557. chia/legacy/__init__.py +0 -0
  558. chia/legacy/keyring.py +155 -0
  559. chia/plot_sync/__init__.py +0 -0
  560. chia/plot_sync/delta.py +61 -0
  561. chia/plot_sync/exceptions.py +56 -0
  562. chia/plot_sync/receiver.py +386 -0
  563. chia/plot_sync/sender.py +340 -0
  564. chia/plot_sync/util.py +43 -0
  565. chia/plotters/__init__.py +0 -0
  566. chia/plotters/bladebit.py +388 -0
  567. chia/plotters/chiapos.py +63 -0
  568. chia/plotters/madmax.py +224 -0
  569. chia/plotters/plotters.py +577 -0
  570. chia/plotters/plotters_util.py +133 -0
  571. chia/plotting/__init__.py +0 -0
  572. chia/plotting/cache.py +213 -0
  573. chia/plotting/check_plots.py +283 -0
  574. chia/plotting/create_plots.py +278 -0
  575. chia/plotting/manager.py +436 -0
  576. chia/plotting/util.py +336 -0
  577. chia/pools/__init__.py +0 -0
  578. chia/pools/pool_config.py +110 -0
  579. chia/pools/pool_puzzles.py +459 -0
  580. chia/pools/pool_wallet.py +933 -0
  581. chia/pools/pool_wallet_info.py +118 -0
  582. chia/pools/puzzles/__init__.py +0 -0
  583. chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
  584. chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
  585. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
  586. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
  587. chia/protocols/__init__.py +0 -0
  588. chia/protocols/farmer_protocol.py +102 -0
  589. chia/protocols/full_node_protocol.py +219 -0
  590. chia/protocols/harvester_protocol.py +216 -0
  591. chia/protocols/introducer_protocol.py +25 -0
  592. chia/protocols/pool_protocol.py +177 -0
  593. chia/protocols/protocol_message_types.py +139 -0
  594. chia/protocols/protocol_state_machine.py +87 -0
  595. chia/protocols/protocol_timing.py +8 -0
  596. chia/protocols/shared_protocol.py +86 -0
  597. chia/protocols/timelord_protocol.py +93 -0
  598. chia/protocols/wallet_protocol.py +401 -0
  599. chia/py.typed +0 -0
  600. chia/rpc/__init__.py +0 -0
  601. chia/rpc/crawler_rpc_api.py +80 -0
  602. chia/rpc/data_layer_rpc_api.py +644 -0
  603. chia/rpc/data_layer_rpc_client.py +188 -0
  604. chia/rpc/data_layer_rpc_util.py +58 -0
  605. chia/rpc/farmer_rpc_api.py +365 -0
  606. chia/rpc/farmer_rpc_client.py +86 -0
  607. chia/rpc/full_node_rpc_api.py +959 -0
  608. chia/rpc/full_node_rpc_client.py +292 -0
  609. chia/rpc/harvester_rpc_api.py +141 -0
  610. chia/rpc/harvester_rpc_client.py +54 -0
  611. chia/rpc/rpc_client.py +164 -0
  612. chia/rpc/rpc_server.py +521 -0
  613. chia/rpc/timelord_rpc_api.py +32 -0
  614. chia/rpc/util.py +93 -0
  615. chia/rpc/wallet_request_types.py +904 -0
  616. chia/rpc/wallet_rpc_api.py +4943 -0
  617. chia/rpc/wallet_rpc_client.py +1814 -0
  618. chia/seeder/__init__.py +0 -0
  619. chia/seeder/crawl_store.py +425 -0
  620. chia/seeder/crawler.py +410 -0
  621. chia/seeder/crawler_api.py +135 -0
  622. chia/seeder/dns_server.py +593 -0
  623. chia/seeder/peer_record.py +146 -0
  624. chia/seeder/start_crawler.py +92 -0
  625. chia/server/__init__.py +0 -0
  626. chia/server/address_manager.py +658 -0
  627. chia/server/address_manager_store.py +237 -0
  628. chia/server/api_protocol.py +116 -0
  629. chia/server/capabilities.py +24 -0
  630. chia/server/chia_policy.py +346 -0
  631. chia/server/introducer_peers.py +76 -0
  632. chia/server/node_discovery.py +714 -0
  633. chia/server/outbound_message.py +33 -0
  634. chia/server/rate_limit_numbers.py +214 -0
  635. chia/server/rate_limits.py +153 -0
  636. chia/server/server.py +741 -0
  637. chia/server/signal_handlers.py +120 -0
  638. chia/server/ssl_context.py +32 -0
  639. chia/server/start_data_layer.py +151 -0
  640. chia/server/start_farmer.py +98 -0
  641. chia/server/start_full_node.py +112 -0
  642. chia/server/start_harvester.py +93 -0
  643. chia/server/start_introducer.py +81 -0
  644. chia/server/start_service.py +316 -0
  645. chia/server/start_timelord.py +89 -0
  646. chia/server/start_wallet.py +113 -0
  647. chia/server/upnp.py +118 -0
  648. chia/server/ws_connection.py +766 -0
  649. chia/simulator/__init__.py +0 -0
  650. chia/simulator/add_blocks_in_batches.py +54 -0
  651. chia/simulator/block_tools.py +2054 -0
  652. chia/simulator/full_node_simulator.py +794 -0
  653. chia/simulator/keyring.py +128 -0
  654. chia/simulator/setup_services.py +506 -0
  655. chia/simulator/simulator_constants.py +13 -0
  656. chia/simulator/simulator_full_node_rpc_api.py +99 -0
  657. chia/simulator/simulator_full_node_rpc_client.py +60 -0
  658. chia/simulator/simulator_protocol.py +29 -0
  659. chia/simulator/simulator_test_tools.py +164 -0
  660. chia/simulator/socket.py +24 -0
  661. chia/simulator/ssl_certs.py +114 -0
  662. chia/simulator/ssl_certs_1.py +697 -0
  663. chia/simulator/ssl_certs_10.py +697 -0
  664. chia/simulator/ssl_certs_2.py +697 -0
  665. chia/simulator/ssl_certs_3.py +697 -0
  666. chia/simulator/ssl_certs_4.py +697 -0
  667. chia/simulator/ssl_certs_5.py +697 -0
  668. chia/simulator/ssl_certs_6.py +697 -0
  669. chia/simulator/ssl_certs_7.py +697 -0
  670. chia/simulator/ssl_certs_8.py +697 -0
  671. chia/simulator/ssl_certs_9.py +697 -0
  672. chia/simulator/start_simulator.py +143 -0
  673. chia/simulator/wallet_tools.py +246 -0
  674. chia/ssl/__init__.py +0 -0
  675. chia/ssl/chia_ca.crt +19 -0
  676. chia/ssl/chia_ca.key +28 -0
  677. chia/ssl/create_ssl.py +249 -0
  678. chia/ssl/dst_root_ca.pem +20 -0
  679. chia/timelord/__init__.py +0 -0
  680. chia/timelord/iters_from_block.py +50 -0
  681. chia/timelord/timelord.py +1226 -0
  682. chia/timelord/timelord_api.py +138 -0
  683. chia/timelord/timelord_launcher.py +190 -0
  684. chia/timelord/timelord_state.py +244 -0
  685. chia/timelord/types.py +22 -0
  686. chia/types/__init__.py +0 -0
  687. chia/types/aliases.py +35 -0
  688. chia/types/block_protocol.py +20 -0
  689. chia/types/blockchain_format/__init__.py +0 -0
  690. chia/types/blockchain_format/classgroup.py +5 -0
  691. chia/types/blockchain_format/coin.py +28 -0
  692. chia/types/blockchain_format/foliage.py +8 -0
  693. chia/types/blockchain_format/pool_target.py +5 -0
  694. chia/types/blockchain_format/program.py +269 -0
  695. chia/types/blockchain_format/proof_of_space.py +135 -0
  696. chia/types/blockchain_format/reward_chain_block.py +6 -0
  697. chia/types/blockchain_format/serialized_program.py +5 -0
  698. chia/types/blockchain_format/sized_bytes.py +11 -0
  699. chia/types/blockchain_format/slots.py +9 -0
  700. chia/types/blockchain_format/sub_epoch_summary.py +5 -0
  701. chia/types/blockchain_format/tree_hash.py +72 -0
  702. chia/types/blockchain_format/vdf.py +86 -0
  703. chia/types/clvm_cost.py +13 -0
  704. chia/types/coin_record.py +43 -0
  705. chia/types/coin_spend.py +115 -0
  706. chia/types/condition_opcodes.py +73 -0
  707. chia/types/condition_with_args.py +16 -0
  708. chia/types/eligible_coin_spends.py +365 -0
  709. chia/types/end_of_slot_bundle.py +5 -0
  710. chia/types/fee_rate.py +38 -0
  711. chia/types/full_block.py +5 -0
  712. chia/types/generator_types.py +13 -0
  713. chia/types/header_block.py +5 -0
  714. chia/types/internal_mempool_item.py +18 -0
  715. chia/types/mempool_inclusion_status.py +9 -0
  716. chia/types/mempool_item.py +85 -0
  717. chia/types/mempool_submission_status.py +30 -0
  718. chia/types/mojos.py +7 -0
  719. chia/types/peer_info.py +64 -0
  720. chia/types/signing_mode.py +29 -0
  721. chia/types/spend_bundle.py +30 -0
  722. chia/types/spend_bundle_conditions.py +7 -0
  723. chia/types/transaction_queue_entry.py +55 -0
  724. chia/types/unfinished_block.py +5 -0
  725. chia/types/unfinished_header_block.py +37 -0
  726. chia/types/validation_state.py +14 -0
  727. chia/types/weight_proof.py +49 -0
  728. chia/util/__init__.py +0 -0
  729. chia/util/action_scope.py +168 -0
  730. chia/util/async_pool.py +226 -0
  731. chia/util/augmented_chain.py +134 -0
  732. chia/util/batches.py +42 -0
  733. chia/util/bech32m.py +126 -0
  734. chia/util/beta_metrics.py +119 -0
  735. chia/util/block_cache.py +56 -0
  736. chia/util/byte_types.py +12 -0
  737. chia/util/check_fork_next_block.py +33 -0
  738. chia/util/chia_logging.py +144 -0
  739. chia/util/chia_version.py +33 -0
  740. chia/util/collection.py +17 -0
  741. chia/util/condition_tools.py +201 -0
  742. chia/util/config.py +367 -0
  743. chia/util/cpu.py +22 -0
  744. chia/util/db_synchronous.py +23 -0
  745. chia/util/db_version.py +32 -0
  746. chia/util/db_wrapper.py +430 -0
  747. chia/util/default_root.py +27 -0
  748. chia/util/dump_keyring.py +93 -0
  749. chia/util/english.txt +2048 -0
  750. chia/util/errors.py +353 -0
  751. chia/util/file_keyring.py +469 -0
  752. chia/util/files.py +97 -0
  753. chia/util/full_block_utils.py +345 -0
  754. chia/util/generator_tools.py +72 -0
  755. chia/util/hash.py +31 -0
  756. chia/util/initial-config.yaml +694 -0
  757. chia/util/inline_executor.py +26 -0
  758. chia/util/ints.py +19 -0
  759. chia/util/ip_address.py +39 -0
  760. chia/util/json_util.py +37 -0
  761. chia/util/keychain.py +676 -0
  762. chia/util/keyring_wrapper.py +327 -0
  763. chia/util/limited_semaphore.py +41 -0
  764. chia/util/lock.py +49 -0
  765. chia/util/log_exceptions.py +32 -0
  766. chia/util/logging.py +36 -0
  767. chia/util/lru_cache.py +31 -0
  768. chia/util/math.py +20 -0
  769. chia/util/network.py +182 -0
  770. chia/util/paginator.py +48 -0
  771. chia/util/path.py +31 -0
  772. chia/util/permissions.py +20 -0
  773. chia/util/prev_transaction_block.py +21 -0
  774. chia/util/priority_mutex.py +95 -0
  775. chia/util/profiler.py +197 -0
  776. chia/util/recursive_replace.py +24 -0
  777. chia/util/safe_cancel_task.py +16 -0
  778. chia/util/service_groups.py +47 -0
  779. chia/util/setproctitle.py +22 -0
  780. chia/util/significant_bits.py +32 -0
  781. chia/util/ssl_check.py +213 -0
  782. chia/util/streamable.py +642 -0
  783. chia/util/task_referencer.py +59 -0
  784. chia/util/task_timing.py +382 -0
  785. chia/util/timing.py +67 -0
  786. chia/util/vdf_prover.py +30 -0
  787. chia/util/virtual_project_analysis.py +540 -0
  788. chia/util/ws_message.py +66 -0
  789. chia/wallet/__init__.py +0 -0
  790. chia/wallet/cat_wallet/__init__.py +0 -0
  791. chia/wallet/cat_wallet/cat_constants.py +75 -0
  792. chia/wallet/cat_wallet/cat_info.py +47 -0
  793. chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
  794. chia/wallet/cat_wallet/cat_utils.py +164 -0
  795. chia/wallet/cat_wallet/cat_wallet.py +855 -0
  796. chia/wallet/cat_wallet/dao_cat_info.py +28 -0
  797. chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
  798. chia/wallet/cat_wallet/lineage_store.py +74 -0
  799. chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
  800. chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
  801. chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
  802. chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
  803. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
  804. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
  805. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
  806. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
  807. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
  808. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
  809. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
  810. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
  811. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
  812. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
  813. chia/wallet/coin_selection.py +188 -0
  814. chia/wallet/conditions.py +1512 -0
  815. chia/wallet/dao_wallet/__init__.py +0 -0
  816. chia/wallet/dao_wallet/dao_info.py +61 -0
  817. chia/wallet/dao_wallet/dao_utils.py +811 -0
  818. chia/wallet/dao_wallet/dao_wallet.py +2119 -0
  819. chia/wallet/db_wallet/__init__.py +0 -0
  820. chia/wallet/db_wallet/db_wallet_puzzles.py +111 -0
  821. chia/wallet/derivation_record.py +30 -0
  822. chia/wallet/derive_keys.py +146 -0
  823. chia/wallet/did_wallet/__init__.py +0 -0
  824. chia/wallet/did_wallet/did_info.py +39 -0
  825. chia/wallet/did_wallet/did_wallet.py +1494 -0
  826. chia/wallet/did_wallet/did_wallet_puzzles.py +221 -0
  827. chia/wallet/did_wallet/puzzles/__init__.py +0 -0
  828. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
  829. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
  830. chia/wallet/driver_protocol.py +26 -0
  831. chia/wallet/key_val_store.py +55 -0
  832. chia/wallet/lineage_proof.py +58 -0
  833. chia/wallet/nft_wallet/__init__.py +0 -0
  834. chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
  835. chia/wallet/nft_wallet/nft_info.py +120 -0
  836. chia/wallet/nft_wallet/nft_puzzles.py +305 -0
  837. chia/wallet/nft_wallet/nft_wallet.py +1687 -0
  838. chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
  839. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  840. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
  841. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
  842. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
  843. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
  844. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
  845. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
  846. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
  847. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
  848. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
  849. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
  850. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
  851. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
  852. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
  853. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
  854. chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
  855. chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
  856. chia/wallet/nft_wallet/uncurry_nft.py +217 -0
  857. chia/wallet/notification_manager.py +117 -0
  858. chia/wallet/notification_store.py +178 -0
  859. chia/wallet/outer_puzzles.py +84 -0
  860. chia/wallet/payment.py +33 -0
  861. chia/wallet/puzzle_drivers.py +118 -0
  862. chia/wallet/puzzles/__init__.py +0 -0
  863. chia/wallet/puzzles/augmented_condition.clsp +13 -0
  864. chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
  865. chia/wallet/puzzles/clawback/__init__.py +0 -0
  866. chia/wallet/puzzles/clawback/drivers.py +188 -0
  867. chia/wallet/puzzles/clawback/metadata.py +38 -0
  868. chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
  869. chia/wallet/puzzles/condition_codes.clib +77 -0
  870. chia/wallet/puzzles/curry-and-treehash.clib +102 -0
  871. chia/wallet/puzzles/curry.clib +135 -0
  872. chia/wallet/puzzles/curry_by_index.clib +16 -0
  873. chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
  874. chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
  875. chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
  876. chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
  877. chia/wallet/puzzles/dao_finished_state.clsp +35 -0
  878. chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
  879. chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
  880. chia/wallet/puzzles/dao_lockup.clsp +288 -0
  881. chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
  882. chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
  883. chia/wallet/puzzles/dao_proposal.clsp +377 -0
  884. chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
  885. chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
  886. chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
  887. chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
  888. chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
  889. chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
  890. chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
  891. chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
  892. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
  893. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
  894. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
  895. chia/wallet/puzzles/dao_treasury.clsp +115 -0
  896. chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
  897. chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
  898. chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
  899. chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
  900. chia/wallet/puzzles/json.clib +25 -0
  901. chia/wallet/puzzles/load_clvm.py +161 -0
  902. chia/wallet/puzzles/merkle_utils.clib +18 -0
  903. chia/wallet/puzzles/notification.clsp +7 -0
  904. chia/wallet/puzzles/notification.clsp.hex +1 -0
  905. chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
  906. chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
  907. chia/wallet/puzzles/p2_conditions.clsp +3 -0
  908. chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
  909. chia/wallet/puzzles/p2_conditions.py +26 -0
  910. chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
  911. chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
  912. chia/wallet/puzzles/p2_delegated_conditions.py +21 -0
  913. chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
  914. chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
  915. chia/wallet/puzzles/p2_delegated_puzzle.py +34 -0
  916. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
  917. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
  918. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +160 -0
  919. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
  920. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
  921. chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +21 -0
  922. chia/wallet/puzzles/p2_parent.clsp +19 -0
  923. chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
  924. chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
  925. chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
  926. chia/wallet/puzzles/p2_puzzle_hash.py +27 -0
  927. chia/wallet/puzzles/p2_singleton.clsp +30 -0
  928. chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
  929. chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
  930. chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
  931. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
  932. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
  933. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
  934. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
  935. chia/wallet/puzzles/puzzle_utils.py +34 -0
  936. chia/wallet/puzzles/settlement_payments.clsp +49 -0
  937. chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
  938. chia/wallet/puzzles/sha256tree.clib +11 -0
  939. chia/wallet/puzzles/singleton_launcher.clsp +16 -0
  940. chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
  941. chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
  942. chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
  943. chia/wallet/puzzles/singleton_top_layer.py +296 -0
  944. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
  945. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
  946. chia/wallet/puzzles/singleton_top_layer_v1_1.py +345 -0
  947. chia/wallet/puzzles/singleton_truths.clib +21 -0
  948. chia/wallet/puzzles/tails.py +348 -0
  949. chia/wallet/puzzles/utility_macros.clib +48 -0
  950. chia/wallet/signer_protocol.py +125 -0
  951. chia/wallet/singleton.py +106 -0
  952. chia/wallet/singleton_record.py +30 -0
  953. chia/wallet/trade_manager.py +1102 -0
  954. chia/wallet/trade_record.py +67 -0
  955. chia/wallet/trading/__init__.py +0 -0
  956. chia/wallet/trading/offer.py +702 -0
  957. chia/wallet/trading/trade_status.py +13 -0
  958. chia/wallet/trading/trade_store.py +526 -0
  959. chia/wallet/transaction_record.py +158 -0
  960. chia/wallet/transaction_sorting.py +14 -0
  961. chia/wallet/uncurried_puzzle.py +17 -0
  962. chia/wallet/util/__init__.py +0 -0
  963. chia/wallet/util/address_type.py +55 -0
  964. chia/wallet/util/blind_signer_tl.py +164 -0
  965. chia/wallet/util/clvm_streamable.py +203 -0
  966. chia/wallet/util/compute_hints.py +66 -0
  967. chia/wallet/util/compute_memos.py +43 -0
  968. chia/wallet/util/curry_and_treehash.py +91 -0
  969. chia/wallet/util/debug_spend_bundle.py +232 -0
  970. chia/wallet/util/merkle_tree.py +100 -0
  971. chia/wallet/util/merkle_utils.py +102 -0
  972. chia/wallet/util/new_peak_queue.py +82 -0
  973. chia/wallet/util/notifications.py +12 -0
  974. chia/wallet/util/peer_request_cache.py +174 -0
  975. chia/wallet/util/pprint.py +39 -0
  976. chia/wallet/util/puzzle_compression.py +95 -0
  977. chia/wallet/util/puzzle_decorator.py +100 -0
  978. chia/wallet/util/puzzle_decorator_type.py +7 -0
  979. chia/wallet/util/query_filter.py +59 -0
  980. chia/wallet/util/transaction_type.py +23 -0
  981. chia/wallet/util/tx_config.py +158 -0
  982. chia/wallet/util/wallet_sync_utils.py +351 -0
  983. chia/wallet/util/wallet_types.py +72 -0
  984. chia/wallet/vc_wallet/__init__.py +0 -0
  985. chia/wallet/vc_wallet/cr_cat_drivers.py +664 -0
  986. chia/wallet/vc_wallet/cr_cat_wallet.py +877 -0
  987. chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
  988. chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
  989. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
  990. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
  991. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
  992. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
  993. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
  994. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
  995. chia/wallet/vc_wallet/vc_drivers.py +838 -0
  996. chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
  997. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
  998. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
  999. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
  1000. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
  1001. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
  1002. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
  1003. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
  1004. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
  1005. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
  1006. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
  1007. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
  1008. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
  1009. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
  1010. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
  1011. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
  1012. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
  1013. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
  1014. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
  1015. chia/wallet/vc_wallet/vc_store.py +263 -0
  1016. chia/wallet/vc_wallet/vc_wallet.py +638 -0
  1017. chia/wallet/wallet.py +698 -0
  1018. chia/wallet/wallet_action_scope.py +96 -0
  1019. chia/wallet/wallet_blockchain.py +244 -0
  1020. chia/wallet/wallet_coin_record.py +72 -0
  1021. chia/wallet/wallet_coin_store.py +351 -0
  1022. chia/wallet/wallet_info.py +35 -0
  1023. chia/wallet/wallet_interested_store.py +188 -0
  1024. chia/wallet/wallet_nft_store.py +279 -0
  1025. chia/wallet/wallet_node.py +1765 -0
  1026. chia/wallet/wallet_node_api.py +207 -0
  1027. chia/wallet/wallet_pool_store.py +119 -0
  1028. chia/wallet/wallet_protocol.py +90 -0
  1029. chia/wallet/wallet_puzzle_store.py +396 -0
  1030. chia/wallet/wallet_retry_store.py +70 -0
  1031. chia/wallet/wallet_singleton_store.py +259 -0
  1032. chia/wallet/wallet_spend_bundle.py +25 -0
  1033. chia/wallet/wallet_state_manager.py +2819 -0
  1034. chia/wallet/wallet_transaction_store.py +496 -0
  1035. chia/wallet/wallet_user_store.py +110 -0
  1036. chia/wallet/wallet_weight_proof_handler.py +126 -0
  1037. chia_blockchain-2.5.1rc1.dist-info/LICENSE +201 -0
  1038. chia_blockchain-2.5.1rc1.dist-info/METADATA +156 -0
  1039. chia_blockchain-2.5.1rc1.dist-info/RECORD +1042 -0
  1040. chia_blockchain-2.5.1rc1.dist-info/WHEEL +4 -0
  1041. chia_blockchain-2.5.1rc1.dist-info/entry_points.txt +17 -0
  1042. mozilla-ca/cacert.pem +3611 -0
@@ -0,0 +1,2584 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import time
5
+ from typing import Any, Callable
6
+
7
+ import pytest
8
+ from chia_rs import AugSchemeMPL, G1Element, G2Element
9
+ from clvm_tools.binutils import disassemble
10
+
11
+ from chia._tests.conftest import ConsensusMode
12
+ from chia._tests.environments.wallet import WalletStateTransition, WalletTestFramework
13
+ from chia._tests.util.time_out_assert import time_out_assert
14
+ from chia.rpc.rpc_client import ResponseFailureError
15
+ from chia.rpc.wallet_request_types import (
16
+ NFTCoin,
17
+ NFTGetByDID,
18
+ NFTSetDIDBulk,
19
+ NFTSetNFTStatus,
20
+ NFTTransferBulk,
21
+ NFTWalletWithDID,
22
+ )
23
+ from chia.simulator.simulator_protocol import ReorgProtocol
24
+ from chia.types.blockchain_format.program import Program
25
+ from chia.types.blockchain_format.sized_bytes import bytes32
26
+ from chia.types.signing_mode import CHIP_0002_SIGN_MESSAGE_PREFIX
27
+ from chia.util.bech32m import decode_puzzle_hash, encode_puzzle_hash
28
+ from chia.util.byte_types import hexstr_to_bytes
29
+ from chia.util.ints import uint32, uint64
30
+ from chia.util.timing import adjusted_timeout
31
+ from chia.wallet.did_wallet.did_wallet import DIDWallet
32
+ from chia.wallet.nft_wallet.nft_info import NFTInfo
33
+ from chia.wallet.nft_wallet.nft_wallet import NFTWallet
34
+ from chia.wallet.util.address_type import AddressType
35
+ from chia.wallet.util.compute_memos import compute_memos
36
+ from chia.wallet.util.wallet_types import WalletType
37
+ from chia.wallet.wallet_state_manager import WalletStateManager
38
+
39
+
40
+ async def get_nft_count(wallet: NFTWallet) -> int:
41
+ return await wallet.get_nft_count()
42
+
43
+
44
+ async def get_wallet_number(manager: WalletStateManager) -> int:
45
+ return len(manager.wallets)
46
+
47
+
48
+ # TODO: This is not a very paradigmatic function and should be updated
49
+ async def wait_rpc_state_condition(
50
+ timeout: float,
51
+ async_function: Any,
52
+ params: list[Any],
53
+ condition_func: Callable[[dict[str, Any]], bool],
54
+ ) -> dict[str, Any]:
55
+ __tracebackhide__ = True
56
+
57
+ timeout = adjusted_timeout(timeout=timeout)
58
+
59
+ start = time.monotonic()
60
+
61
+ while True:
62
+ resp = await async_function(*params)
63
+ assert isinstance(resp, dict)
64
+ if condition_func(resp):
65
+ return resp
66
+
67
+ now = time.monotonic()
68
+ elapsed = now - start
69
+ if elapsed >= timeout:
70
+ raise asyncio.TimeoutError(
71
+ f"timed out while waiting for {async_function.__name__}(): {elapsed} >= {timeout}",
72
+ )
73
+
74
+ await asyncio.sleep(0.3)
75
+
76
+
77
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
78
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
79
+ @pytest.mark.anyio
80
+ async def test_nft_wallet_creation_automatically(wallet_environments: WalletTestFramework) -> None:
81
+ env_0 = wallet_environments.environments[0]
82
+ env_1 = wallet_environments.environments[1]
83
+ wallet_node_0 = env_0.node
84
+ wallet_node_1 = env_1.node
85
+ wallet_0 = env_0.xch_wallet
86
+ wallet_1 = env_1.xch_wallet
87
+
88
+ env_0.wallet_aliases = {
89
+ "xch": 1,
90
+ "nft": 2,
91
+ }
92
+ env_1.wallet_aliases = {
93
+ "xch": 1,
94
+ "nft": 2,
95
+ }
96
+
97
+ nft_wallet_0 = await NFTWallet.create_new_nft_wallet(
98
+ wallet_node_0.wallet_state_manager, wallet_0, name="NFT WALLET 1"
99
+ )
100
+ metadata = Program.to(
101
+ [("u", ["https://www.chia.net/img/branding/chia-logo.svg"]), ("h", "0xD4584AD463139FA8C0D9F68F4B59F185")]
102
+ )
103
+
104
+ async with nft_wallet_0.wallet_state_manager.new_action_scope(
105
+ wallet_environments.tx_config, push=True
106
+ ) as action_scope:
107
+ await nft_wallet_0.generate_new_nft(metadata, action_scope)
108
+
109
+ await wallet_environments.process_pending_states(
110
+ [
111
+ WalletStateTransition(
112
+ pre_block_balance_updates={
113
+ "xch": {
114
+ "confirmed_wallet_balance": 0,
115
+ "unconfirmed_wallet_balance": -1,
116
+ "<=#spendable_balance": -1,
117
+ "<=#max_send_amount": -1,
118
+ "pending_coin_removal_count": 1,
119
+ ">=#pending_change": 1, # any amount increase
120
+ "unspent_coin_count": 0,
121
+ },
122
+ "nft": {
123
+ "init": True,
124
+ "confirmed_wallet_balance": 0,
125
+ "unconfirmed_wallet_balance": 0,
126
+ "spendable_balance": 0,
127
+ "max_send_amount": 0,
128
+ "pending_coin_removal_count": 1, # a bit weird but correct?
129
+ "pending_change": 0,
130
+ "unspent_coin_count": 0,
131
+ },
132
+ },
133
+ post_block_balance_updates={
134
+ "xch": {
135
+ "confirmed_wallet_balance": -1,
136
+ "unconfirmed_wallet_balance": 0,
137
+ ">=#spendable_balance": 1, # any amount increase
138
+ ">=#max_send_amount": 1, # any amount increase
139
+ "pending_coin_removal_count": -1,
140
+ "<=#pending_change": -1, # any amount decrease
141
+ "unspent_coin_count": 0,
142
+ },
143
+ "nft": {
144
+ "pending_coin_removal_count": -1,
145
+ "unspent_coin_count": 1,
146
+ },
147
+ },
148
+ ),
149
+ WalletStateTransition(),
150
+ ]
151
+ )
152
+
153
+ await time_out_assert(30, get_nft_count, 1, nft_wallet_0)
154
+ coins = await nft_wallet_0.get_current_nfts()
155
+ assert len(coins) == 1, "nft not generated"
156
+
157
+ async with nft_wallet_0.wallet_state_manager.new_action_scope(
158
+ wallet_environments.tx_config, push=True
159
+ ) as action_scope:
160
+ await nft_wallet_0.generate_signed_transaction(
161
+ [uint64(coins[0].coin.amount)],
162
+ [await wallet_1.get_puzzle_hash(new=False)],
163
+ action_scope,
164
+ coins={coins[0].coin},
165
+ )
166
+
167
+ await wallet_environments.process_pending_states(
168
+ [
169
+ WalletStateTransition(
170
+ pre_block_balance_updates={
171
+ "xch": {},
172
+ "nft": {
173
+ "pending_coin_removal_count": 1,
174
+ },
175
+ },
176
+ post_block_balance_updates={
177
+ "xch": {},
178
+ "nft": {
179
+ "pending_coin_removal_count": -1,
180
+ "unspent_coin_count": -1,
181
+ },
182
+ },
183
+ ),
184
+ WalletStateTransition(
185
+ pre_block_balance_updates={
186
+ "xch": {},
187
+ },
188
+ post_block_balance_updates={
189
+ "xch": {},
190
+ "nft": {
191
+ "init": True,
192
+ "unspent_coin_count": 1,
193
+ },
194
+ },
195
+ ),
196
+ ]
197
+ )
198
+
199
+ async def num_wallets() -> int:
200
+ return len(await wallet_node_1.wallet_state_manager.get_all_wallet_info_entries())
201
+
202
+ await time_out_assert(30, num_wallets, 2)
203
+ # Get the new NFT wallet
204
+ nft_wallets = await wallet_node_1.wallet_state_manager.get_all_wallet_info_entries(WalletType.NFT)
205
+ assert len(nft_wallets) == 1
206
+ nft_wallet_1 = wallet_node_1.wallet_state_manager.wallets[nft_wallets[0].id]
207
+ assert isinstance(nft_wallet_1, NFTWallet)
208
+ await time_out_assert(30, get_nft_count, 0, nft_wallet_0)
209
+ await time_out_assert(30, get_nft_count, 1, nft_wallet_1)
210
+
211
+ assert await nft_wallet_0.get_nft_count() == 0
212
+ assert await nft_wallet_1.get_nft_count() == 1
213
+
214
+
215
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
216
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
217
+ @pytest.mark.anyio
218
+ async def test_nft_wallet_creation_and_transfer(wallet_environments: WalletTestFramework) -> None:
219
+ env_0 = wallet_environments.environments[0]
220
+ env_1 = wallet_environments.environments[1]
221
+ full_node_api = wallet_environments.full_node
222
+ wallet_node_0 = env_0.node
223
+ wallet_node_1 = env_1.node
224
+ wallet_0 = env_0.xch_wallet
225
+ wallet_1 = env_1.xch_wallet
226
+
227
+ env_0.wallet_aliases = {
228
+ "xch": 1,
229
+ "nft": 2,
230
+ }
231
+ env_1.wallet_aliases = {
232
+ "xch": 1,
233
+ "nft": 2,
234
+ }
235
+
236
+ nft_wallet_0 = await NFTWallet.create_new_nft_wallet(
237
+ wallet_node_0.wallet_state_manager, wallet_0, name="NFT WALLET 1"
238
+ )
239
+ metadata = Program.to(
240
+ [("u", ["https://www.chia.net/img/branding/chia-logo.svg"]), ("h", "0xD4584AD463139FA8C0D9F68F4B59F185")]
241
+ )
242
+ async with nft_wallet_0.wallet_state_manager.new_action_scope(
243
+ wallet_environments.tx_config, push=True
244
+ ) as action_scope:
245
+ await nft_wallet_0.generate_new_nft(metadata, action_scope)
246
+ for tx in action_scope.side_effects.transactions:
247
+ if tx.spend_bundle is not None:
248
+ # ensure hints are generated
249
+ assert len(compute_memos(tx.spend_bundle)) > 0
250
+
251
+ await wallet_environments.process_pending_states(
252
+ [
253
+ WalletStateTransition(
254
+ pre_block_balance_updates={
255
+ "xch": {
256
+ "confirmed_wallet_balance": 0,
257
+ "unconfirmed_wallet_balance": -1,
258
+ "<=#spendable_balance": -1,
259
+ "<=#max_send_amount": -1,
260
+ "pending_coin_removal_count": 1,
261
+ ">=#pending_change": 1, # any amount increase
262
+ "unspent_coin_count": 0,
263
+ },
264
+ "nft": {
265
+ "init": True,
266
+ "confirmed_wallet_balance": 0,
267
+ "unconfirmed_wallet_balance": 0,
268
+ "spendable_balance": 0,
269
+ "max_send_amount": 0,
270
+ "pending_coin_removal_count": 1,
271
+ "pending_change": 0,
272
+ "unspent_coin_count": 0,
273
+ },
274
+ },
275
+ post_block_balance_updates={
276
+ "xch": {
277
+ "confirmed_wallet_balance": -1,
278
+ "unconfirmed_wallet_balance": 0,
279
+ ">=#spendable_balance": 1, # any amount increase
280
+ ">=#max_send_amount": 1, # any amount increase
281
+ "pending_coin_removal_count": -1,
282
+ "<=#pending_change": -1, # any amount decrease
283
+ "unspent_coin_count": 0,
284
+ },
285
+ "nft": {
286
+ "pending_coin_removal_count": -1,
287
+ "unspent_coin_count": 1,
288
+ },
289
+ },
290
+ ),
291
+ WalletStateTransition(),
292
+ ]
293
+ )
294
+
295
+ await time_out_assert(10, get_nft_count, 1, nft_wallet_0)
296
+
297
+ # Test Reorg mint
298
+ height = full_node_api.full_node.blockchain.get_peak_height()
299
+ assert height is not None
300
+ await full_node_api.reorg_from_index_to_new_index(
301
+ ReorgProtocol(uint32(height - 1), uint32(height + 1), bytes32.zeros, None)
302
+ )
303
+ await time_out_assert(60, full_node_api.full_node.blockchain.get_peak_height, height + 1)
304
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, peak_height=uint32(height + 1), timeout=10)
305
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_1, peak_height=uint32(height + 1), timeout=10)
306
+ await env_0.change_balances(
307
+ {
308
+ "xch": {
309
+ "set_remainder": True, # Not testing XCH reorg functionality in this test
310
+ },
311
+ "nft": {
312
+ # State back to before confirmation
313
+ "unspent_coin_count": -1,
314
+ "pending_coin_removal_count": 1,
315
+ },
316
+ }
317
+ )
318
+ await env_0.check_balances()
319
+
320
+ await time_out_assert(30, get_nft_count, 0, nft_wallet_0)
321
+ await time_out_assert(30, get_wallet_number, 2, wallet_node_0.wallet_state_manager)
322
+
323
+ new_metadata = Program.to([("u", ["https://www.test.net/logo.svg"]), ("h", "0xD4584AD463139FA8C0D9F68F4B59F181")])
324
+
325
+ async with nft_wallet_0.wallet_state_manager.new_action_scope(
326
+ wallet_environments.tx_config, push=True
327
+ ) as action_scope:
328
+ await nft_wallet_0.generate_new_nft(new_metadata, action_scope)
329
+ for tx in action_scope.side_effects.transactions:
330
+ if tx.spend_bundle is not None:
331
+ # ensure hints are generated
332
+ assert len(compute_memos(tx.spend_bundle)) > 0
333
+
334
+ await wallet_environments.process_pending_states(
335
+ [
336
+ WalletStateTransition(
337
+ pre_block_balance_updates={
338
+ "xch": {
339
+ "confirmed_wallet_balance": 0,
340
+ "unconfirmed_wallet_balance": -1,
341
+ "<=#spendable_balance": -1,
342
+ "<=#max_send_amount": -1,
343
+ "pending_coin_removal_count": 1,
344
+ ">=#pending_change": 1, # any amount increase
345
+ "unspent_coin_count": 0,
346
+ },
347
+ "nft": {
348
+ "pending_coin_removal_count": 1,
349
+ },
350
+ },
351
+ post_block_balance_updates={
352
+ "xch": {
353
+ "confirmed_wallet_balance": -2,
354
+ "unconfirmed_wallet_balance": 0,
355
+ ">=#spendable_balance": 1, # any amount increase
356
+ ">=#max_send_amount": 1, # any amount increase
357
+ "pending_coin_removal_count": -2,
358
+ "<=#pending_change": -1, # any amount decrease
359
+ "unspent_coin_count": 0,
360
+ },
361
+ "nft": {
362
+ "pending_coin_removal_count": -2,
363
+ "unspent_coin_count": 2,
364
+ },
365
+ },
366
+ ),
367
+ WalletStateTransition(),
368
+ ]
369
+ )
370
+
371
+ await time_out_assert(30, get_nft_count, 2, nft_wallet_0)
372
+ coins = await nft_wallet_0.get_current_nfts()
373
+ assert len(coins) == 2, "nft not generated"
374
+
375
+ nft_wallet_1 = await NFTWallet.create_new_nft_wallet(
376
+ wallet_node_1.wallet_state_manager, wallet_1, name="NFT WALLET 2"
377
+ )
378
+ async with nft_wallet_0.wallet_state_manager.new_action_scope(
379
+ wallet_environments.tx_config, push=True
380
+ ) as action_scope:
381
+ await nft_wallet_0.generate_signed_transaction(
382
+ [uint64(coins[1].coin.amount)],
383
+ [await wallet_1.get_puzzle_hash(False)],
384
+ action_scope,
385
+ coins={coins[1].coin},
386
+ )
387
+ assert action_scope.side_effects.transactions[0].spend_bundle is not None
388
+
389
+ assert len(compute_memos(action_scope.side_effects.transactions[0].spend_bundle)) > 0
390
+
391
+ await wallet_environments.process_pending_states(
392
+ [
393
+ WalletStateTransition(
394
+ pre_block_balance_updates={
395
+ "nft": {
396
+ "pending_coin_removal_count": 1,
397
+ }
398
+ },
399
+ post_block_balance_updates={
400
+ "nft": {
401
+ "pending_coin_removal_count": -1,
402
+ "unspent_coin_count": -1,
403
+ }
404
+ },
405
+ ),
406
+ WalletStateTransition(
407
+ pre_block_balance_updates={
408
+ "nft": {
409
+ "init": True,
410
+ "confirmed_wallet_balance": 0,
411
+ "unconfirmed_wallet_balance": 0,
412
+ "spendable_balance": 0,
413
+ "max_send_amount": 0,
414
+ "pending_coin_removal_count": 0,
415
+ "pending_change": 0,
416
+ "unspent_coin_count": 0,
417
+ }
418
+ },
419
+ post_block_balance_updates={
420
+ "nft": {
421
+ "unspent_coin_count": 1,
422
+ }
423
+ },
424
+ ),
425
+ ]
426
+ )
427
+
428
+ await time_out_assert(30, get_nft_count, 1, nft_wallet_0)
429
+ await time_out_assert(30, get_nft_count, 1, nft_wallet_1)
430
+
431
+ coins = await nft_wallet_1.get_current_nfts()
432
+ assert len(coins) == 1
433
+
434
+ # Send it back to original owner
435
+ async with nft_wallet_1.wallet_state_manager.new_action_scope(
436
+ wallet_environments.tx_config, push=True
437
+ ) as action_scope:
438
+ await nft_wallet_1.generate_signed_transaction(
439
+ [uint64(coins[0].coin.amount)],
440
+ [await wallet_0.get_puzzle_hash(False)],
441
+ action_scope,
442
+ coins={coins[0].coin},
443
+ )
444
+ assert action_scope.side_effects.transactions[0].spend_bundle is not None
445
+
446
+ assert len(compute_memos(action_scope.side_effects.transactions[0].spend_bundle)) > 0
447
+
448
+ await wallet_environments.process_pending_states(
449
+ [
450
+ WalletStateTransition(
451
+ pre_block_balance_updates={},
452
+ post_block_balance_updates={
453
+ "nft": {
454
+ "unspent_coin_count": 1,
455
+ }
456
+ },
457
+ ),
458
+ WalletStateTransition(
459
+ pre_block_balance_updates={
460
+ "nft": {
461
+ "pending_coin_removal_count": 1,
462
+ }
463
+ },
464
+ post_block_balance_updates={
465
+ "nft": {
466
+ "pending_coin_removal_count": -1,
467
+ "unspent_coin_count": -1,
468
+ }
469
+ },
470
+ ),
471
+ ]
472
+ )
473
+
474
+ await time_out_assert(30, get_nft_count, 2, nft_wallet_0)
475
+ await time_out_assert(30, get_nft_count, 0, nft_wallet_1)
476
+
477
+ # Test Reorg
478
+ height = full_node_api.full_node.blockchain.get_peak_height()
479
+ assert height is not None
480
+ await full_node_api.reorg_from_index_to_new_index(
481
+ ReorgProtocol(uint32(height - 1), uint32(height + 2), bytes32.zeros, None)
482
+ )
483
+
484
+ await full_node_api.wait_for_self_synced()
485
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_0, peak_height=uint32(height + 2))
486
+ await full_node_api.wait_for_wallet_synced(wallet_node=wallet_node_1, peak_height=uint32(height + 2))
487
+
488
+ await env_0.change_balances(
489
+ {
490
+ "nft": {
491
+ "unspent_coin_count": -1,
492
+ }
493
+ }
494
+ )
495
+ await env_1.change_balances(
496
+ {
497
+ "nft": {
498
+ "pending_coin_removal_count": 1,
499
+ "unspent_coin_count": 1,
500
+ }
501
+ }
502
+ )
503
+ await env_0.check_balances()
504
+ await env_1.check_balances()
505
+
506
+ await time_out_assert(30, get_nft_count, 1, nft_wallet_0)
507
+ await time_out_assert(30, get_nft_count, 1, nft_wallet_1)
508
+
509
+
510
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
511
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
512
+ @pytest.mark.anyio
513
+ async def test_nft_wallet_rpc_creation_and_list(wallet_environments: WalletTestFramework) -> None:
514
+ env = wallet_environments.environments[0]
515
+ wallet_node = env.node
516
+ wallet = env.xch_wallet
517
+
518
+ env.wallet_aliases = {
519
+ "xch": 1,
520
+ "nft": 2,
521
+ }
522
+
523
+ nft_wallet_0 = await env.rpc_client.fetch("create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1"))
524
+ assert isinstance(nft_wallet_0, dict)
525
+ assert nft_wallet_0.get("success")
526
+ assert env.wallet_aliases["nft"] == nft_wallet_0["wallet_id"]
527
+
528
+ await env.rpc_client.mint_nft(
529
+ wallet_id=env.wallet_aliases["nft"],
530
+ royalty_address=encode_puzzle_hash(
531
+ await wallet.get_puzzle_hash(new=False), AddressType.NFT.hrp(wallet_node.config)
532
+ ),
533
+ target_address=None,
534
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
535
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
536
+ tx_config=wallet_environments.tx_config,
537
+ )
538
+
539
+ await wallet_environments.process_pending_states(
540
+ [
541
+ WalletStateTransition(
542
+ pre_block_balance_updates={
543
+ "xch": {"set_remainder": True}, # tested above
544
+ "nft": {"init": True, "pending_coin_removal_count": 1},
545
+ },
546
+ post_block_balance_updates={
547
+ "xch": {"set_remainder": True}, # tested above
548
+ "nft": {
549
+ "pending_coin_removal_count": -1,
550
+ "unspent_coin_count": 1,
551
+ },
552
+ },
553
+ )
554
+ ]
555
+ )
556
+
557
+ await wait_rpc_state_condition(
558
+ 30, env.rpc_client.fetch, ["nft_get_nfts", dict(wallet_id=env.wallet_aliases["nft"])], lambda x: x["nft_list"]
559
+ )
560
+ second_mint = await env.rpc_client.mint_nft(
561
+ wallet_id=env.wallet_aliases["nft"],
562
+ royalty_address=encode_puzzle_hash(
563
+ await wallet.get_puzzle_hash(new=False), AddressType.NFT.hrp(wallet_node.config)
564
+ ),
565
+ target_address=None,
566
+ tx_config=wallet_environments.tx_config,
567
+ hash="0xD4584AD463139FA8C0D9F68F4B59F184",
568
+ uris=["https://chialisp.com/img/logo.svg"],
569
+ meta_uris=[
570
+ "https://bafybeigzcazxeu7epmm4vtkuadrvysv74lbzzbl2evphtae6k57yhgynp4.ipfs.nftstorage.link/6590.json"
571
+ ],
572
+ meta_hash="0x6a9cb99b7b9a987309e8dd4fd14a7ca2423858585da68cc9ec689669dd6dd6ab",
573
+ )
574
+
575
+ await wallet_environments.process_pending_states(
576
+ [
577
+ WalletStateTransition(
578
+ pre_block_balance_updates={
579
+ "xch": {"set_remainder": True}, # tested above
580
+ "nft": {"pending_coin_removal_count": 1},
581
+ },
582
+ post_block_balance_updates={
583
+ "xch": {"set_remainder": True}, # tested above
584
+ "nft": {
585
+ "pending_coin_removal_count": -1,
586
+ "unspent_coin_count": 1,
587
+ },
588
+ },
589
+ )
590
+ ]
591
+ )
592
+
593
+ coins_response = await wait_rpc_state_condition(
594
+ 30,
595
+ env.rpc_client.fetch,
596
+ ["nft_get_nfts", dict(wallet_id=env.wallet_aliases["nft"])],
597
+ lambda x: x["success"] and len(x["nft_list"]) == 2,
598
+ )
599
+ coins: list[NFTInfo] = [NFTInfo.from_json_dict(d) for d in coins_response["nft_list"]]
600
+ uris = []
601
+ for coin in coins:
602
+ assert not coin.supports_did
603
+ uris.append(coin.data_uris[0])
604
+ assert coin.mint_height > 0
605
+ assert len(uris) == 2
606
+ assert "https://chialisp.com/img/logo.svg" in uris
607
+ assert bytes32.fromhex(coins[1].to_json_dict()["nft_coin_id"][2:]) in [
608
+ x.name() for x in second_mint.spend_bundle.additions()
609
+ ]
610
+
611
+ coins_response = await wait_rpc_state_condition(
612
+ 5,
613
+ env.rpc_client.fetch,
614
+ ["nft_get_nfts", {"wallet_id": env.wallet_aliases["nft"], "start_index": 1, "num": 1}],
615
+ lambda x: x["success"] and len(x["nft_list"]) == 1,
616
+ )
617
+ coins = [NFTInfo.from_json_dict(d) for d in coins_response["nft_list"]]
618
+ assert len(coins) == 1
619
+ assert coins[0].data_hash.hex() == "0xD4584AD463139FA8C0D9F68F4B59F184"[2:].lower()
620
+
621
+ # test counts
622
+
623
+ resp = await wait_rpc_state_condition(
624
+ 10, env.rpc_client.fetch, ["nft_count_nfts", {"wallet_id": env.wallet_aliases["nft"]}], lambda x: x["success"]
625
+ )
626
+ assert resp["count"] == 2
627
+ resp = await wait_rpc_state_condition(10, env.rpc_client.fetch, ["nft_count_nfts", {}], lambda x: x["success"])
628
+ assert resp["count"] == 2
629
+ with pytest.raises(ResponseFailureError, match="Wallet 50 not found."):
630
+ resp = await wait_rpc_state_condition(
631
+ 10, env.rpc_client.fetch, ["nft_count_nfts", {"wallet_id": 50}], lambda x: x["success"] is False
632
+ )
633
+
634
+
635
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
636
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
637
+ @pytest.mark.anyio
638
+ async def test_nft_wallet_rpc_update_metadata(wallet_environments: WalletTestFramework) -> None:
639
+ env = wallet_environments.environments[0]
640
+ wallet_node = env.node
641
+ wallet = env.xch_wallet
642
+
643
+ env.wallet_aliases = {
644
+ "xch": 1,
645
+ "nft": 2,
646
+ }
647
+
648
+ nft_wallet = await NFTWallet.create_new_nft_wallet(wallet_node.wallet_state_manager, wallet, name="NFT WALLET 1")
649
+
650
+ await env.rpc_client.mint_nft(
651
+ wallet_id=nft_wallet.id(),
652
+ royalty_address=None,
653
+ target_address=None,
654
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
655
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
656
+ tx_config=wallet_environments.tx_config,
657
+ )
658
+
659
+ await wallet_environments.process_pending_states(
660
+ [
661
+ WalletStateTransition(
662
+ pre_block_balance_updates={
663
+ "xch": {"set_remainder": True},
664
+ "nft": {"init": True, "pending_coin_removal_count": 1},
665
+ },
666
+ post_block_balance_updates={
667
+ "xch": {"set_remainder": True},
668
+ "nft": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
669
+ },
670
+ )
671
+ ]
672
+ )
673
+
674
+ coins: list[dict[str, Any]] = (await env.rpc_client.list_nfts(nft_wallet.id(), start_index=0, num=1))["nft_list"]
675
+ coin = coins[0]
676
+ assert coin["mint_height"] > 0
677
+ assert coin["data_hash"] == "0xd4584ad463139fa8c0d9f68f4b59f185"
678
+ assert coin["chain_info"] == disassemble(
679
+ Program.to(
680
+ [
681
+ ("u", ["https://www.chia.net/img/branding/chia-logo.svg"]),
682
+ ("h", hexstr_to_bytes("0xD4584AD463139FA8C0D9F68F4B59F185")),
683
+ ("mu", []),
684
+ ("lu", []),
685
+ ("sn", uint64(1)),
686
+ ("st", uint64(1)),
687
+ ]
688
+ )
689
+ )
690
+
691
+ nft_coin_id = encode_puzzle_hash(bytes32.from_hexstr(coin["nft_coin_id"]), AddressType.NFT.hrp(env.node.config))
692
+ await env.rpc_client.add_uri_to_nft(
693
+ wallet_id=nft_wallet.id(),
694
+ nft_coin_id=nft_coin_id,
695
+ uri="http://metadata",
696
+ key="mu",
697
+ fee=0,
698
+ tx_config=wallet_environments.tx_config,
699
+ )
700
+
701
+ coins = (await env.rpc_client.list_nfts(nft_wallet.id(), start_index=0, num=1))["nft_list"]
702
+ assert coins[0]["pending_transaction"]
703
+
704
+ await wallet_environments.process_pending_states(
705
+ [
706
+ WalletStateTransition(
707
+ pre_block_balance_updates={
708
+ "xch": {},
709
+ "nft": {"pending_coin_removal_count": 1},
710
+ },
711
+ post_block_balance_updates={
712
+ "xch": {},
713
+ "nft": {"pending_coin_removal_count": -1},
714
+ },
715
+ ),
716
+ ]
717
+ )
718
+
719
+ # check that new URI was added
720
+ coins = (await env.rpc_client.list_nfts(nft_wallet.id(), start_index=0, num=1))["nft_list"]
721
+ assert len(coins) == 1
722
+ coin = coins[0]
723
+ assert coin["mint_height"] > 0
724
+ uris = coin["data_uris"]
725
+ assert len(uris) == 1
726
+ assert "https://www.chia.net/img/branding/chia-logo.svg" in uris
727
+ assert len(coin["metadata_uris"]) == 1
728
+ assert "http://metadata" == coin["metadata_uris"][0]
729
+ assert len(coin["license_uris"]) == 0
730
+
731
+ # add yet another URI, this time using a hex nft_coin_id
732
+ nft_coin_id = coin["nft_coin_id"]
733
+ await env.rpc_client.add_uri_to_nft(
734
+ wallet_id=nft_wallet.id(),
735
+ nft_coin_id=nft_coin_id,
736
+ uri="http://data",
737
+ key="u",
738
+ fee=0,
739
+ tx_config=wallet_environments.tx_config,
740
+ )
741
+
742
+ await wallet_environments.process_pending_states(
743
+ [
744
+ WalletStateTransition(
745
+ pre_block_balance_updates={
746
+ "xch": {},
747
+ "nft": {"pending_coin_removal_count": 1},
748
+ },
749
+ post_block_balance_updates={
750
+ "xch": {},
751
+ "nft": {"pending_coin_removal_count": -1},
752
+ },
753
+ ),
754
+ ]
755
+ )
756
+
757
+ coins = (await env.rpc_client.list_nfts(nft_wallet.id(), start_index=0, num=1))["nft_list"]
758
+ assert len(coins) == 1
759
+ coin = coins[0]
760
+ assert coin["mint_height"] > 0
761
+ uris = coin["data_uris"]
762
+ assert len(uris) == 2
763
+ assert len(coin["metadata_uris"]) == 1
764
+ assert "http://data" == coin["data_uris"][0]
765
+
766
+
767
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
768
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
769
+ @pytest.mark.anyio
770
+ async def test_nft_with_did_wallet_creation(wallet_environments: WalletTestFramework) -> None:
771
+ env = wallet_environments.environments[0]
772
+ wallet_node = env.node
773
+ wallet = env.xch_wallet
774
+
775
+ env.wallet_aliases = {
776
+ "xch": 1,
777
+ "did": 2,
778
+ "nft_w_did": 3,
779
+ "nft_no_did": 4,
780
+ }
781
+
782
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
783
+ did_wallet = await DIDWallet.create_new_did_wallet(env.wallet_state_manager, wallet, uint64(1), action_scope)
784
+
785
+ # use "set_remainder" here because this is more of a DID test issue
786
+ await wallet_environments.process_pending_states(
787
+ [
788
+ WalletStateTransition(
789
+ pre_block_balance_updates={
790
+ "xch": {"set_remainder": True},
791
+ "did": {"init": True, "set_remainder": True},
792
+ },
793
+ post_block_balance_updates={
794
+ "xch": {"set_remainder": True},
795
+ "did": {"set_remainder": True},
796
+ },
797
+ )
798
+ ]
799
+ )
800
+
801
+ hex_did_id = did_wallet.get_my_DID()
802
+ did_id = bytes32.from_hexstr(hex_did_id)
803
+ hmr_did_id = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id), AddressType.DID.hrp(env.node.config))
804
+
805
+ nft_wallet = await NFTWallet.create_new_nft_wallet(
806
+ wallet_node.wallet_state_manager, wallet, name="NFT WALLET 1", did_id=did_id
807
+ )
808
+
809
+ # this shouldn't work
810
+ res = await env.rpc_client.fetch(
811
+ "create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1", did_id=hmr_did_id)
812
+ )
813
+ assert res["wallet_id"] == nft_wallet.id()
814
+
815
+ await wallet_environments.process_pending_states(
816
+ [
817
+ WalletStateTransition(
818
+ pre_block_balance_updates={"nft_w_did": {"init": True}},
819
+ post_block_balance_updates={},
820
+ )
821
+ ]
822
+ )
823
+
824
+ # now create NFT wallet with P2 standard puzzle for inner puzzle
825
+ res = await env.rpc_client.fetch("create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 0"))
826
+ assert res["wallet_id"] != nft_wallet.id()
827
+ nft_wallet_p2_puzzle = res["wallet_id"]
828
+
829
+ wallet_by_did_response = await env.rpc_client.get_nft_wallet_by_did(NFTGetByDID(did_id=hmr_did_id))
830
+ assert nft_wallet.id() == wallet_by_did_response.wallet_id
831
+
832
+ await wallet_environments.process_pending_states(
833
+ [
834
+ WalletStateTransition(
835
+ pre_block_balance_updates={"nft_no_did": {"init": True}},
836
+ post_block_balance_updates={},
837
+ )
838
+ ]
839
+ )
840
+
841
+ assert (await env.rpc_client.get_nft_wallets_with_dids()).nft_wallets == [
842
+ NFTWalletWithDID(wallet_id=nft_wallet.id(), did_id=hmr_did_id, did_wallet_id=did_wallet.id())
843
+ ]
844
+
845
+ res = await env.rpc_client.get_nft_wallet_did(wallet_id=nft_wallet.id())
846
+ assert res.get("did_id") == hmr_did_id
847
+
848
+ # Create a NFT with DID
849
+ nft_ph = await wallet.get_puzzle_hash(new=False)
850
+ resp = await env.rpc_client.mint_nft(
851
+ wallet_id=nft_wallet.id(),
852
+ royalty_address=None,
853
+ target_address=encode_puzzle_hash(nft_ph, "txch"),
854
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
855
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
856
+ tx_config=wallet_environments.tx_config,
857
+ )
858
+ # ensure hints are generated correctly
859
+ memos = compute_memos(resp.spend_bundle)
860
+ assert len(memos) > 0
861
+ puzhashes = []
862
+ for x in memos.values():
863
+ puzhashes.extend(list(x))
864
+ assert len(puzhashes) > 0
865
+ matched = 0
866
+ for puzhash in puzhashes:
867
+ if puzhash.hex() == nft_ph.hex():
868
+ matched += 1
869
+ assert matched > 0
870
+
871
+ await wallet_environments.process_pending_states(
872
+ [
873
+ WalletStateTransition(
874
+ pre_block_balance_updates={
875
+ "xch": {"set_remainder": True},
876
+ "did": {
877
+ "spendable_balance": -1,
878
+ "pending_change": 1,
879
+ "pending_coin_removal_count": 1,
880
+ "max_send_amount": -1,
881
+ },
882
+ "nft_w_did": {"pending_coin_removal_count": 1},
883
+ },
884
+ post_block_balance_updates={
885
+ "xch": {"set_remainder": True},
886
+ "did": {
887
+ "spendable_balance": 1,
888
+ "pending_change": -1,
889
+ "pending_coin_removal_count": -1,
890
+ "max_send_amount": 1,
891
+ },
892
+ "nft_w_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
893
+ },
894
+ )
895
+ ]
896
+ )
897
+ # Create a NFT without DID, this will go the unassigned NFT wallet
898
+ resp = await env.rpc_client.mint_nft(
899
+ wallet_id=nft_wallet.id(),
900
+ royalty_address=None,
901
+ target_address=None,
902
+ hash="0xD4584AD463139FA8C0D9F68F4B59F181",
903
+ uris=["https://url1"],
904
+ did_id="",
905
+ tx_config=wallet_environments.tx_config,
906
+ )
907
+
908
+ # ensure hints are generated
909
+ assert len(compute_memos(resp.spend_bundle)) > 0
910
+
911
+ # TODO: the "pending_coin_removal_count" here is a bit weird. I think it's right
912
+ # but it might be worth refactoring the minting flow generally to only add transaction
913
+ # records for the xch wallet rather than some arbitrary nft wallet.
914
+ await wallet_environments.process_pending_states(
915
+ [
916
+ WalletStateTransition(
917
+ pre_block_balance_updates={
918
+ "xch": {"set_remainder": True},
919
+ "did": {},
920
+ "nft_w_did": {"pending_coin_removal_count": 1},
921
+ "nft_no_did": {},
922
+ },
923
+ post_block_balance_updates={
924
+ "xch": {"set_remainder": True},
925
+ "did": {},
926
+ "nft_w_did": {"pending_coin_removal_count": -1},
927
+ "nft_no_did": {"unspent_coin_count": 1},
928
+ },
929
+ )
930
+ ]
931
+ )
932
+ # Check DID NFT
933
+ coins: list[dict[str, Any]] = (await env.rpc_client.list_nfts(nft_wallet.id(), start_index=0, num=1))["nft_list"]
934
+ assert len(coins) == 1
935
+ did_nft = coins[0]
936
+ assert did_nft["mint_height"] > 0
937
+ assert did_nft["supports_did"]
938
+ assert did_nft["data_uris"][0] == "https://www.chia.net/img/branding/chia-logo.svg"
939
+ assert did_nft["data_hash"] == "0xD4584AD463139FA8C0D9F68F4B59F185".lower()
940
+ assert did_nft["owner_did"][2:] == hex_did_id
941
+ # Check unassigned NFT
942
+ nft_wallets = await env.wallet_state_manager.get_all_wallet_info_entries(WalletType.NFT)
943
+ assert len(nft_wallets) == 2
944
+ coins_response = await env.rpc_client.list_nfts(nft_wallet_p2_puzzle, start_index=0, num=1)
945
+ assert coins_response["nft_list"]
946
+ assert coins_response.get("success")
947
+ coins = coins_response["nft_list"]
948
+ assert len(coins) == 1
949
+ non_did_nft = coins[0]
950
+ assert non_did_nft["mint_height"] > 0
951
+ assert non_did_nft["supports_did"]
952
+ assert non_did_nft["data_uris"][0] == "https://url1"
953
+ assert non_did_nft["data_hash"] == "0xD4584AD463139FA8C0D9F68F4B59F181".lower()
954
+ assert non_did_nft["owner_did"] is None
955
+
956
+
957
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
958
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
959
+ @pytest.mark.anyio
960
+ async def test_nft_rpc_mint(wallet_environments: WalletTestFramework) -> None:
961
+ env = wallet_environments.environments[0]
962
+ wallet = env.xch_wallet
963
+
964
+ env.wallet_aliases = {
965
+ "xch": 1,
966
+ "did": 2,
967
+ "nft_w_did": 3,
968
+ "nft_no_did": 4,
969
+ }
970
+
971
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
972
+ did_wallet = await DIDWallet.create_new_did_wallet(env.wallet_state_manager, wallet, uint64(1), action_scope)
973
+
974
+ # use "set_remainder" here because this is more of a DID test issue
975
+ await wallet_environments.process_pending_states(
976
+ [
977
+ WalletStateTransition(
978
+ pre_block_balance_updates={
979
+ "xch": {"set_remainder": True},
980
+ "did": {"init": True, "set_remainder": True},
981
+ },
982
+ post_block_balance_updates={
983
+ "xch": {"set_remainder": True},
984
+ "did": {"set_remainder": True},
985
+ },
986
+ )
987
+ ]
988
+ )
989
+
990
+ did_id = encode_puzzle_hash(bytes32.from_hexstr(did_wallet.get_my_DID()), AddressType.DID.hrp(env.node.config))
991
+
992
+ res = await env.rpc_client.fetch(
993
+ "create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1", did_id=did_id)
994
+ )
995
+ assert isinstance(res, dict)
996
+ assert res.get("success")
997
+ assert env.wallet_aliases["nft_w_did"] == res["wallet_id"]
998
+
999
+ await wallet_environments.process_pending_states(
1000
+ [
1001
+ WalletStateTransition(
1002
+ pre_block_balance_updates={"nft_w_did": {"init": True}},
1003
+ post_block_balance_updates={},
1004
+ )
1005
+ ]
1006
+ )
1007
+
1008
+ # Create a NFT with DID
1009
+ royalty_address = await wallet.get_puzzle_hash(new=False)
1010
+ royalty_bech32 = encode_puzzle_hash(royalty_address, AddressType.NFT.hrp(env.node.config))
1011
+ data_hash_param = "0xD4584AD463139FA8C0D9F68F4B59F185"
1012
+ license_uris = ["http://mylicenseuri"]
1013
+ license_hash = "0xcafef00d"
1014
+ meta_uris = ["http://metauri"]
1015
+ meta_hash = "0xdeadbeef"
1016
+ royalty_percentage = 200
1017
+ sn = 10
1018
+ st = 100
1019
+ resp = await env.rpc_client.mint_nft(
1020
+ wallet_id=env.wallet_aliases["nft_w_did"],
1021
+ royalty_address=royalty_bech32,
1022
+ target_address=royalty_bech32, # doesn't matter so we'll just reuse
1023
+ hash=data_hash_param,
1024
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1025
+ tx_config=wallet_environments.tx_config,
1026
+ meta_hash=meta_hash,
1027
+ meta_uris=meta_uris,
1028
+ license_hash=license_hash,
1029
+ license_uris=license_uris,
1030
+ edition_total=st,
1031
+ edition_number=sn,
1032
+ royalty_percentage=royalty_percentage,
1033
+ )
1034
+ nft_id = resp.nft_id
1035
+
1036
+ # ensure hints are generated
1037
+ assert len(compute_memos(resp.spend_bundle)) > 0
1038
+
1039
+ await wallet_environments.process_pending_states(
1040
+ [
1041
+ WalletStateTransition(
1042
+ pre_block_balance_updates={
1043
+ "xch": {"set_remainder": True},
1044
+ "did": {
1045
+ "spendable_balance": -1,
1046
+ "pending_change": 1,
1047
+ "pending_coin_removal_count": 1,
1048
+ "max_send_amount": -1,
1049
+ },
1050
+ "nft_w_did": {"pending_coin_removal_count": 1},
1051
+ },
1052
+ post_block_balance_updates={
1053
+ "xch": {"set_remainder": True},
1054
+ "did": {
1055
+ "spendable_balance": 1,
1056
+ "pending_change": -1,
1057
+ "pending_coin_removal_count": -1,
1058
+ "max_send_amount": 1,
1059
+ },
1060
+ "nft_w_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1061
+ },
1062
+ )
1063
+ ]
1064
+ )
1065
+
1066
+ coins: list[dict[str, Any]] = (
1067
+ await env.rpc_client.list_nfts(env.wallet_aliases["nft_w_did"], start_index=0, num=1)
1068
+ )["nft_list"]
1069
+ assert len(coins) == 1
1070
+ did_nft = NFTInfo.from_json_dict(coins[0])
1071
+ assert did_nft.royalty_puzzle_hash == royalty_address
1072
+ assert did_nft.data_hash == bytes.fromhex(data_hash_param[2:])
1073
+ assert did_nft.metadata_hash == bytes.fromhex(meta_hash[2:])
1074
+ assert did_nft.metadata_uris == meta_uris
1075
+ assert did_nft.license_uris == license_uris
1076
+ assert did_nft.license_hash == bytes.fromhex(license_hash[2:])
1077
+ assert did_nft.edition_total == st
1078
+ assert did_nft.edition_number == sn
1079
+ assert did_nft.royalty_percentage == royalty_percentage
1080
+ assert decode_puzzle_hash(nft_id) == did_nft.launcher_id
1081
+
1082
+
1083
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1084
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
1085
+ @pytest.mark.anyio
1086
+ async def test_nft_transfer_nft_with_did(wallet_environments: WalletTestFramework) -> None:
1087
+ env_0 = wallet_environments.environments[0]
1088
+ env_1 = wallet_environments.environments[1]
1089
+ wallet_0 = env_0.xch_wallet
1090
+ wallet_1 = env_1.xch_wallet
1091
+
1092
+ env_0.wallet_aliases = {
1093
+ "xch": 1,
1094
+ "did": 2,
1095
+ "nft": 3,
1096
+ }
1097
+ env_1.wallet_aliases = {
1098
+ "xch": 1,
1099
+ "did": 2,
1100
+ "nft": 3,
1101
+ "nft_w_did": 4,
1102
+ }
1103
+ # Create DID
1104
+ async with wallet_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1105
+ did_wallet = await DIDWallet.create_new_did_wallet(
1106
+ env_0.wallet_state_manager, wallet_0, uint64(1), action_scope
1107
+ )
1108
+
1109
+ # use "set_remainder" here because this is more of a DID test issue
1110
+ await wallet_environments.process_pending_states(
1111
+ [
1112
+ WalletStateTransition(
1113
+ pre_block_balance_updates={
1114
+ "xch": {"set_remainder": True},
1115
+ "did": {"init": True, "set_remainder": True},
1116
+ },
1117
+ post_block_balance_updates={
1118
+ "xch": {"set_remainder": True},
1119
+ "did": {"set_remainder": True},
1120
+ },
1121
+ ),
1122
+ WalletStateTransition(),
1123
+ ]
1124
+ )
1125
+
1126
+ hex_did_id = did_wallet.get_my_DID()
1127
+ hmr_did_id = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id), AddressType.DID.hrp(env_0.node.config))
1128
+
1129
+ # Create NFT wallet
1130
+ res = await env_0.rpc_client.fetch(
1131
+ "create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1", did_id=hmr_did_id)
1132
+ )
1133
+ assert isinstance(res, dict)
1134
+ assert res.get("success")
1135
+ assert env_0.wallet_aliases["nft"] == res["wallet_id"]
1136
+
1137
+ await wallet_environments.process_pending_states(
1138
+ [
1139
+ WalletStateTransition(
1140
+ pre_block_balance_updates={
1141
+ "nft": {"init": True},
1142
+ },
1143
+ post_block_balance_updates={},
1144
+ ),
1145
+ WalletStateTransition(),
1146
+ ]
1147
+ )
1148
+
1149
+ # Create a NFT with DID
1150
+ fee = 100
1151
+ await env_0.rpc_client.mint_nft(
1152
+ wallet_id=env_0.wallet_aliases["nft"],
1153
+ royalty_address=None,
1154
+ target_address=None, # doesn't matter so we'll just reuse
1155
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1156
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1157
+ tx_config=wallet_environments.tx_config,
1158
+ fee=fee,
1159
+ did_id=hmr_did_id,
1160
+ )
1161
+
1162
+ await wallet_environments.process_pending_states(
1163
+ [
1164
+ WalletStateTransition(
1165
+ pre_block_balance_updates={
1166
+ "xch": {
1167
+ "unconfirmed_wallet_balance": -fee - 1,
1168
+ "<=#spendable_balance": -fee - 1,
1169
+ ">=#pending_change": 1, # any amount increase
1170
+ "<=#max_send_amount": -fee - 1,
1171
+ "pending_coin_removal_count": 1,
1172
+ },
1173
+ "did": {
1174
+ "spendable_balance": -1,
1175
+ "pending_change": 1,
1176
+ "pending_coin_removal_count": 1,
1177
+ "max_send_amount": -1,
1178
+ },
1179
+ "nft": {"pending_coin_removal_count": 1},
1180
+ },
1181
+ post_block_balance_updates={
1182
+ "xch": {
1183
+ "confirmed_wallet_balance": -fee - 1,
1184
+ ">=#spendable_balance": 1, # any amount increase
1185
+ "<=#pending_change": -1, # any amount decrease
1186
+ ">=#max_send_amount": 1, # any amount increase
1187
+ "pending_coin_removal_count": -1,
1188
+ },
1189
+ "did": {
1190
+ "spendable_balance": 1,
1191
+ "pending_change": -1,
1192
+ "pending_coin_removal_count": -1,
1193
+ "max_send_amount": 1,
1194
+ },
1195
+ "nft": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1196
+ },
1197
+ ),
1198
+ WalletStateTransition(),
1199
+ ]
1200
+ )
1201
+
1202
+ # Check DID NFT
1203
+ coins: list[dict[str, Any]] = (await env_0.rpc_client.list_nfts(env_0.wallet_aliases["nft"], start_index=0, num=1))[
1204
+ "nft_list"
1205
+ ]
1206
+ assert len(coins) == 1
1207
+ coin = NFTInfo.from_json_dict(coins[0])
1208
+ assert coin.owner_did is not None
1209
+ assert coin.owner_did.hex() == hex_did_id
1210
+
1211
+ assert len(env_1.wallet_state_manager.wallets) == 1, "NFT wallet shouldn't exist yet"
1212
+ assert len(env_0.wallet_state_manager.wallets) == 3
1213
+
1214
+ # transfer DID to the other wallet
1215
+ async with did_wallet.wallet_state_manager.new_action_scope(
1216
+ wallet_environments.tx_config, push=True
1217
+ ) as action_scope:
1218
+ await did_wallet.transfer_did(await wallet_1.get_puzzle_hash(new=False), uint64(0), True, action_scope)
1219
+
1220
+ await wallet_environments.process_pending_states(
1221
+ [
1222
+ WalletStateTransition(
1223
+ pre_block_balance_updates={
1224
+ "did": {
1225
+ "unconfirmed_wallet_balance": -1,
1226
+ "spendable_balance": -1,
1227
+ "pending_coin_removal_count": 1,
1228
+ "max_send_amount": -1,
1229
+ }
1230
+ },
1231
+ post_block_balance_updates={}, # DID wallet is deleted
1232
+ ),
1233
+ WalletStateTransition(
1234
+ pre_block_balance_updates={},
1235
+ post_block_balance_updates={
1236
+ "did": {
1237
+ "init": True,
1238
+ "set_remainder": True, # only important to test creation
1239
+ }
1240
+ },
1241
+ ),
1242
+ ]
1243
+ )
1244
+
1245
+ # Transfer NFT, wallet will be deleted
1246
+ mint_resp = await env_0.rpc_client.transfer_nft(
1247
+ wallet_id=env_0.wallet_aliases["nft"],
1248
+ nft_coin_id=coin.nft_coin_id.hex(),
1249
+ target_address=encode_puzzle_hash(await wallet_1.get_puzzle_hash(new=False), "xch"),
1250
+ fee=fee,
1251
+ tx_config=wallet_environments.tx_config,
1252
+ )
1253
+ assert len(compute_memos(mint_resp.spend_bundle)) > 0
1254
+
1255
+ await wallet_environments.process_pending_states(
1256
+ [
1257
+ WalletStateTransition(
1258
+ pre_block_balance_updates={
1259
+ "xch": {
1260
+ "unconfirmed_wallet_balance": -fee,
1261
+ "<=#spendable_balance": -fee,
1262
+ ">=#pending_change": 1, # any amount increase
1263
+ "<=#max_send_amount": -fee,
1264
+ "pending_coin_removal_count": 1,
1265
+ },
1266
+ "nft": {"pending_coin_removal_count": 1},
1267
+ },
1268
+ post_block_balance_updates={
1269
+ "xch": {
1270
+ "confirmed_wallet_balance": -fee,
1271
+ ">=#spendable_balance": 1, # any amount increase
1272
+ "<=#pending_change": -1, # any amount decrease
1273
+ ">=#max_send_amount": 1, # any amount increase
1274
+ "pending_coin_removal_count": -1,
1275
+ }
1276
+ # nft wallet deleted
1277
+ },
1278
+ ),
1279
+ WalletStateTransition(
1280
+ pre_block_balance_updates={},
1281
+ post_block_balance_updates={
1282
+ "nft": {"init": True, "unspent_coin_count": 1},
1283
+ },
1284
+ ),
1285
+ ]
1286
+ )
1287
+
1288
+ # Check if the NFT owner DID is reset
1289
+ wallet_by_did_response = await env_1.rpc_client.get_nft_wallet_by_did(NFTGetByDID())
1290
+ assert env_1.wallet_aliases["nft"] == wallet_by_did_response.wallet_id
1291
+ coins = (await env_1.rpc_client.list_nfts(env_1.wallet_aliases["nft"], start_index=0, num=1))["nft_list"]
1292
+ assert len(coins) == 1
1293
+ coin = NFTInfo.from_json_dict(coins[0])
1294
+ assert coin.owner_did is None
1295
+ assert coin.minter_did is not None
1296
+ assert coin.minter_did.hex() == hex_did_id
1297
+ nft_coin_id = coin.nft_coin_id
1298
+
1299
+ # Set DID
1300
+ await env_1.rpc_client.set_nft_did(
1301
+ wallet_id=env_1.wallet_aliases["nft"],
1302
+ did_id=hmr_did_id,
1303
+ nft_coin_id=nft_coin_id.hex(),
1304
+ fee=fee,
1305
+ tx_config=wallet_environments.tx_config,
1306
+ )
1307
+
1308
+ await wallet_environments.process_pending_states(
1309
+ [
1310
+ WalletStateTransition(),
1311
+ WalletStateTransition(
1312
+ pre_block_balance_updates={
1313
+ "xch": {
1314
+ "unconfirmed_wallet_balance": -fee,
1315
+ "<=#spendable_balance": -fee,
1316
+ ">=#pending_change": 1, # any amount increase
1317
+ "<=#max_send_amount": -fee,
1318
+ "pending_coin_removal_count": 1,
1319
+ },
1320
+ "did": {
1321
+ "spendable_balance": -1,
1322
+ "pending_change": 1,
1323
+ "pending_coin_removal_count": 1,
1324
+ "max_send_amount": -1,
1325
+ },
1326
+ "nft": {"pending_coin_removal_count": 1},
1327
+ },
1328
+ post_block_balance_updates={
1329
+ "xch": {
1330
+ "confirmed_wallet_balance": -fee,
1331
+ ">=#spendable_balance": 1, # any amount increase
1332
+ "<=#pending_change": -1, # any amount decrease
1333
+ ">=#max_send_amount": 1, # any amount increase
1334
+ "pending_coin_removal_count": -1,
1335
+ },
1336
+ "did": {
1337
+ "spendable_balance": 1,
1338
+ "pending_change": -1,
1339
+ "pending_coin_removal_count": -1,
1340
+ "max_send_amount": 1,
1341
+ },
1342
+ "nft": {"pending_coin_removal_count": -1, "unspent_coin_count": -1},
1343
+ "nft_w_did": {"init": True, "unspent_coin_count": 1},
1344
+ },
1345
+ ),
1346
+ ]
1347
+ )
1348
+
1349
+ wallet_by_did_response = await env_1.rpc_client.get_nft_wallet_by_did(NFTGetByDID(did_id=hmr_did_id))
1350
+ assert env_1.wallet_aliases["nft_w_did"] == wallet_by_did_response.wallet_id
1351
+ # Check NFT DID is set now
1352
+ coins = (await env_1.rpc_client.list_nfts(env_1.wallet_aliases["nft_w_did"], start_index=0, num=1))["nft_list"]
1353
+ assert len(coins) == 1
1354
+ coin = NFTInfo.from_json_dict(coins[0])
1355
+ assert coin.owner_did is not None
1356
+ assert coin.owner_did.hex() == hex_did_id
1357
+
1358
+
1359
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1360
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1361
+ @pytest.mark.anyio
1362
+ async def test_update_metadata_for_nft_did(wallet_environments: WalletTestFramework) -> None:
1363
+ env = wallet_environments.environments[0]
1364
+ wallet = env.xch_wallet
1365
+
1366
+ env.wallet_aliases = {
1367
+ "xch": 1,
1368
+ "did": 2,
1369
+ "nft": 3,
1370
+ }
1371
+
1372
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1373
+ did_wallet = await DIDWallet.create_new_did_wallet(env.wallet_state_manager, wallet, uint64(1), action_scope)
1374
+
1375
+ # use "set_remainder" here because this is more of a DID test issue
1376
+ await wallet_environments.process_pending_states(
1377
+ [
1378
+ WalletStateTransition(
1379
+ pre_block_balance_updates={
1380
+ "xch": {"set_remainder": True},
1381
+ "did": {"init": True, "set_remainder": True},
1382
+ },
1383
+ post_block_balance_updates={
1384
+ "xch": {"set_remainder": True},
1385
+ "did": {"set_remainder": True},
1386
+ },
1387
+ ),
1388
+ ]
1389
+ )
1390
+
1391
+ hex_did_id = did_wallet.get_my_DID()
1392
+ hmr_did_id = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id), AddressType.DID.hrp(env.node.config))
1393
+
1394
+ # Create NFT wallet
1395
+ res = await env.rpc_client.fetch(
1396
+ "create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1", did_id=hmr_did_id)
1397
+ )
1398
+ assert isinstance(res, dict)
1399
+ assert res.get("success")
1400
+ assert env.wallet_aliases["nft"] == res["wallet_id"]
1401
+
1402
+ await wallet_environments.process_pending_states(
1403
+ [
1404
+ WalletStateTransition(
1405
+ pre_block_balance_updates={
1406
+ "nft": {"init": True},
1407
+ },
1408
+ post_block_balance_updates={},
1409
+ ),
1410
+ ]
1411
+ )
1412
+
1413
+ # Create a NFT with DID
1414
+ mint_resp = await env.rpc_client.mint_nft(
1415
+ wallet_id=env.wallet_aliases["nft"],
1416
+ royalty_address=None,
1417
+ target_address=None, # doesn't matter so we'll just reuse
1418
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1419
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1420
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1421
+ tx_config=wallet_environments.tx_config,
1422
+ did_id=hmr_did_id,
1423
+ )
1424
+
1425
+ # ensure hints are generated
1426
+ assert len(compute_memos(mint_resp.spend_bundle)) > 0
1427
+
1428
+ await wallet_environments.process_pending_states(
1429
+ [
1430
+ WalletStateTransition(
1431
+ pre_block_balance_updates={
1432
+ "xch": {
1433
+ "unconfirmed_wallet_balance": -1,
1434
+ "<=#spendable_balance": -1,
1435
+ ">=#pending_change": 1, # any amount increase
1436
+ "<=#max_send_amount": -1,
1437
+ "pending_coin_removal_count": 1,
1438
+ },
1439
+ "did": {
1440
+ "spendable_balance": -1,
1441
+ "pending_change": 1,
1442
+ "pending_coin_removal_count": 1,
1443
+ "max_send_amount": -1,
1444
+ },
1445
+ "nft": {"pending_coin_removal_count": 1},
1446
+ },
1447
+ post_block_balance_updates={
1448
+ "xch": {
1449
+ "confirmed_wallet_balance": -1,
1450
+ ">=#spendable_balance": 1, # any amount increase
1451
+ "<=#pending_change": -1, # any amount decrease
1452
+ ">=#max_send_amount": 1, # any amount increase
1453
+ "pending_coin_removal_count": -1,
1454
+ },
1455
+ "did": {
1456
+ "spendable_balance": 1,
1457
+ "pending_change": -1,
1458
+ "pending_coin_removal_count": -1,
1459
+ "max_send_amount": 1,
1460
+ },
1461
+ "nft": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1462
+ },
1463
+ ),
1464
+ ]
1465
+ )
1466
+
1467
+ # Check DID NFT
1468
+
1469
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft"], start_index=0, num=1))["nft_list"]
1470
+ assert len(coins) == 1
1471
+ coin = NFTInfo.from_json_dict(coins[0])
1472
+ assert coin.minter_did is not None
1473
+ assert coin.minter_did.hex() == hex_did_id
1474
+ nft_coin_id = coin.nft_coin_id
1475
+
1476
+ # add another URI
1477
+ fee = 100
1478
+ await env.rpc_client.add_uri_to_nft(
1479
+ wallet_id=env.wallet_aliases["nft"],
1480
+ nft_coin_id=nft_coin_id.hex(),
1481
+ key="mu",
1482
+ uri="http://metadata",
1483
+ fee=fee,
1484
+ tx_config=wallet_environments.tx_config,
1485
+ )
1486
+
1487
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft"], start_index=0, num=1))["nft_list"]
1488
+ assert len(coins) == 1
1489
+ coin = NFTInfo.from_json_dict(coins[0])
1490
+ assert coin.pending_transaction
1491
+
1492
+ await wallet_environments.process_pending_states(
1493
+ [
1494
+ WalletStateTransition(
1495
+ pre_block_balance_updates={
1496
+ "xch": {
1497
+ "unconfirmed_wallet_balance": -fee,
1498
+ "<=#spendable_balance": -fee,
1499
+ ">=#pending_change": 1, # any amount increase
1500
+ "<=#max_send_amount": -fee,
1501
+ "pending_coin_removal_count": 1,
1502
+ },
1503
+ "nft": {"pending_coin_removal_count": 1},
1504
+ },
1505
+ post_block_balance_updates={
1506
+ "xch": {
1507
+ "confirmed_wallet_balance": -fee,
1508
+ ">=#spendable_balance": 1, # any amount increase
1509
+ "<=#pending_change": -1, # any amount decrease
1510
+ ">=#max_send_amount": 1, # any amount increase
1511
+ "pending_coin_removal_count": -1,
1512
+ },
1513
+ "nft": {"pending_coin_removal_count": -1},
1514
+ },
1515
+ ),
1516
+ ]
1517
+ )
1518
+
1519
+ # check that new URI was added
1520
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft"], start_index=0, num=1))["nft_list"]
1521
+ assert len(coins) == 1
1522
+
1523
+ assert coins[0]["minter_did"][2:] == hex_did_id
1524
+ assert coins[0]["mint_height"] > 0
1525
+ uris = coins[0]["data_uris"]
1526
+ assert len(uris) == 1
1527
+ assert "https://www.chia.net/img/branding/chia-logo.svg" in uris
1528
+ assert len(coins[0]["metadata_uris"]) == 2
1529
+ assert "http://metadata" == coins[0]["metadata_uris"][0]
1530
+ assert len(coins[0]["license_uris"]) == 0
1531
+
1532
+
1533
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1534
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
1535
+ @pytest.mark.anyio
1536
+ async def test_nft_bulk_set_did(wallet_environments: WalletTestFramework) -> None:
1537
+ env = wallet_environments.environments[0]
1538
+ wallet = env.xch_wallet
1539
+
1540
+ env.wallet_aliases = {
1541
+ "xch": 1,
1542
+ "did": 2,
1543
+ "nft_w_did": 3,
1544
+ "nft_no_did": 4,
1545
+ }
1546
+
1547
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1548
+ did_wallet = await DIDWallet.create_new_did_wallet(env.wallet_state_manager, wallet, uint64(1), action_scope)
1549
+
1550
+ # use "set_remainder" here because this is more of a DID test issue
1551
+ await wallet_environments.process_pending_states(
1552
+ [
1553
+ WalletStateTransition(
1554
+ pre_block_balance_updates={
1555
+ "xch": {"set_remainder": True},
1556
+ "did": {"init": True, "set_remainder": True},
1557
+ },
1558
+ post_block_balance_updates={
1559
+ "xch": {"set_remainder": True},
1560
+ "did": {"set_remainder": True},
1561
+ },
1562
+ ),
1563
+ ]
1564
+ )
1565
+
1566
+ hex_did_id = did_wallet.get_my_DID()
1567
+ hmr_did_id = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id), AddressType.DID.hrp(env.node.config))
1568
+ res = await env.rpc_client.fetch(
1569
+ "create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1", did_id=hmr_did_id)
1570
+ )
1571
+ assert isinstance(res, dict)
1572
+ assert res.get("success")
1573
+ assert env.wallet_aliases["nft_w_did"] == res["wallet_id"]
1574
+ res = await env.rpc_client.fetch("create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 2"))
1575
+ assert isinstance(res, dict)
1576
+ assert res.get("success")
1577
+ assert env.wallet_aliases["nft_no_did"] == res["wallet_id"]
1578
+
1579
+ await wallet_environments.process_pending_states(
1580
+ [
1581
+ WalletStateTransition(
1582
+ pre_block_balance_updates={
1583
+ "nft_w_did": {"init": True},
1584
+ "nft_no_did": {"init": True},
1585
+ },
1586
+ post_block_balance_updates={},
1587
+ ),
1588
+ ]
1589
+ )
1590
+
1591
+ # Create an NFT with DID
1592
+ mint_resp_1 = await env.rpc_client.mint_nft(
1593
+ wallet_id=env.wallet_aliases["nft_w_did"],
1594
+ royalty_address=None,
1595
+ target_address=None, # doesn't matter so we'll just reuse
1596
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1597
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1598
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1599
+ tx_config=wallet_environments.tx_config,
1600
+ did_id=hmr_did_id,
1601
+ )
1602
+ assert len(compute_memos(mint_resp_1.spend_bundle)) > 0
1603
+
1604
+ await wallet_environments.process_pending_states(
1605
+ [
1606
+ WalletStateTransition(
1607
+ pre_block_balance_updates={
1608
+ "xch": {
1609
+ "unconfirmed_wallet_balance": -1,
1610
+ "<=#spendable_balance": -1,
1611
+ ">=#pending_change": 1, # any amount increase
1612
+ "<=#max_send_amount": -1,
1613
+ "pending_coin_removal_count": 1,
1614
+ },
1615
+ "did": {
1616
+ "spendable_balance": -1,
1617
+ "pending_change": 1,
1618
+ "pending_coin_removal_count": 1,
1619
+ "max_send_amount": -1,
1620
+ },
1621
+ "nft_w_did": {"pending_coin_removal_count": 1},
1622
+ },
1623
+ post_block_balance_updates={
1624
+ "xch": {
1625
+ "confirmed_wallet_balance": -1,
1626
+ ">=#spendable_balance": 1, # any amount increase
1627
+ "<=#pending_change": -1, # any amount decrease
1628
+ ">=#max_send_amount": 1, # any amount increase
1629
+ "pending_coin_removal_count": -1,
1630
+ },
1631
+ "did": {
1632
+ "spendable_balance": 1,
1633
+ "pending_change": -1,
1634
+ "pending_coin_removal_count": -1,
1635
+ "max_send_amount": 1,
1636
+ },
1637
+ "nft_w_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1638
+ },
1639
+ )
1640
+ ]
1641
+ )
1642
+
1643
+ # And one w/o
1644
+ mint_resp_2 = await env.rpc_client.mint_nft(
1645
+ wallet_id=env.wallet_aliases["nft_no_did"],
1646
+ royalty_address=None,
1647
+ target_address=None, # doesn't matter so we'll just reuse
1648
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1649
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1650
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1651
+ tx_config=wallet_environments.tx_config,
1652
+ did_id="",
1653
+ )
1654
+ assert len(compute_memos(mint_resp_2.spend_bundle)) > 0
1655
+
1656
+ await wallet_environments.process_pending_states(
1657
+ [
1658
+ WalletStateTransition(
1659
+ pre_block_balance_updates={
1660
+ "xch": {
1661
+ "unconfirmed_wallet_balance": -1,
1662
+ "<=#spendable_balance": -1,
1663
+ ">=#pending_change": 1, # any amount increase
1664
+ "<=#max_send_amount": -1,
1665
+ "pending_coin_removal_count": 1,
1666
+ },
1667
+ "nft_no_did": {"pending_coin_removal_count": 1},
1668
+ },
1669
+ post_block_balance_updates={
1670
+ "xch": {
1671
+ "confirmed_wallet_balance": -1,
1672
+ ">=#spendable_balance": 1, # any amount increase
1673
+ "<=#pending_change": -1, # any amount decrease
1674
+ ">=#max_send_amount": 1, # any amount increase
1675
+ "pending_coin_removal_count": -1,
1676
+ },
1677
+ "nft_no_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1678
+ },
1679
+ )
1680
+ ]
1681
+ )
1682
+
1683
+ # Make a second one w/ DID to test "bulk" updating in same wallet
1684
+ mint_resp_3 = await env.rpc_client.mint_nft(
1685
+ wallet_id=env.wallet_aliases["nft_w_did"],
1686
+ royalty_address=None,
1687
+ target_address=None, # doesn't matter so we'll just reuse
1688
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1689
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1690
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1691
+ tx_config=wallet_environments.tx_config,
1692
+ did_id=hmr_did_id,
1693
+ )
1694
+ assert len(compute_memos(mint_resp_3.spend_bundle)) > 0
1695
+
1696
+ await wallet_environments.process_pending_states(
1697
+ [
1698
+ WalletStateTransition(
1699
+ pre_block_balance_updates={
1700
+ "xch": {
1701
+ "unconfirmed_wallet_balance": -1,
1702
+ "<=#spendable_balance": -1,
1703
+ ">=#pending_change": 1, # any amount increase
1704
+ "<=#max_send_amount": -1,
1705
+ "pending_coin_removal_count": 1,
1706
+ },
1707
+ "did": {
1708
+ "spendable_balance": -1,
1709
+ "pending_change": 1,
1710
+ "pending_coin_removal_count": 1,
1711
+ "max_send_amount": -1,
1712
+ },
1713
+ "nft_w_did": {"pending_coin_removal_count": 1},
1714
+ },
1715
+ post_block_balance_updates={
1716
+ "xch": {
1717
+ "confirmed_wallet_balance": -1,
1718
+ ">=#spendable_balance": 1, # any amount increase
1719
+ "<=#pending_change": -1, # any amount decrease
1720
+ ">=#max_send_amount": 1, # any amount increase
1721
+ "pending_coin_removal_count": -1,
1722
+ },
1723
+ "did": {
1724
+ "spendable_balance": 1,
1725
+ "pending_change": -1,
1726
+ "pending_coin_removal_count": -1,
1727
+ "max_send_amount": 1,
1728
+ },
1729
+ "nft_w_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1730
+ },
1731
+ )
1732
+ ]
1733
+ )
1734
+
1735
+ # Check DID NFT
1736
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_w_did"], start_index=0, num=2))["nft_list"]
1737
+ assert len(coins) == 2
1738
+ nft1 = NFTInfo.from_json_dict(coins[0])
1739
+ nft12 = NFTInfo.from_json_dict(coins[1])
1740
+ assert nft1.owner_did is not None
1741
+ assert nft12.owner_did is not None
1742
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_no_did"], start_index=0, num=1))["nft_list"]
1743
+ assert len(coins) == 1
1744
+ nft2 = NFTInfo.from_json_dict(coins[0])
1745
+ assert nft2.owner_did is None
1746
+ nft_coin_list = [
1747
+ NFTCoin(wallet_id=uint32(env.wallet_aliases["nft_w_did"]), nft_coin_id=nft1.nft_coin_id.hex()),
1748
+ NFTCoin(wallet_id=uint32(env.wallet_aliases["nft_w_did"]), nft_coin_id=nft12.nft_coin_id.hex()),
1749
+ NFTCoin(wallet_id=uint32(env.wallet_aliases["nft_no_did"]), nft_coin_id=nft2.nft_coin_id.hex()),
1750
+ ]
1751
+ fee = uint64(1000)
1752
+ set_did_bulk_resp = await env.rpc_client.set_nft_did_bulk(
1753
+ NFTSetDIDBulk(did_id=hmr_did_id, nft_coin_list=nft_coin_list, fee=fee, push=True),
1754
+ wallet_environments.tx_config,
1755
+ )
1756
+ assert len(set_did_bulk_resp.spend_bundle.coin_spends) == 5
1757
+ assert set_did_bulk_resp.tx_num == 5 # 1 for each NFT being spent (3), 1 for fee tx, 1 for did tx
1758
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_w_did"], start_index=0, num=2))["nft_list"]
1759
+ assert len(coins) == 2
1760
+ nft1 = NFTInfo.from_json_dict(coins[0])
1761
+ nft12 = NFTInfo.from_json_dict(coins[1])
1762
+ assert nft1.pending_transaction
1763
+ assert nft12.pending_transaction
1764
+
1765
+ await wallet_environments.process_pending_states(
1766
+ [
1767
+ WalletStateTransition(
1768
+ pre_block_balance_updates={
1769
+ "xch": {
1770
+ "unconfirmed_wallet_balance": -fee,
1771
+ "<=#spendable_balance": -fee,
1772
+ ">=#pending_change": 1, # any amount increase
1773
+ "<=#max_send_amount": -fee,
1774
+ "pending_coin_removal_count": 1,
1775
+ },
1776
+ "did": {
1777
+ "spendable_balance": -1,
1778
+ "pending_change": 1,
1779
+ "pending_coin_removal_count": 1,
1780
+ "max_send_amount": -1,
1781
+ },
1782
+ "nft_w_did": {"pending_coin_removal_count": 2},
1783
+ "nft_no_did": {"pending_coin_removal_count": 1},
1784
+ },
1785
+ post_block_balance_updates={
1786
+ "xch": {
1787
+ "confirmed_wallet_balance": -fee,
1788
+ ">=#spendable_balance": 1, # any amount increase
1789
+ "<=#pending_change": -1, # any amount decrease
1790
+ ">=#max_send_amount": 1, # any amount increase
1791
+ "pending_coin_removal_count": -1,
1792
+ },
1793
+ "did": {
1794
+ "spendable_balance": 1,
1795
+ "pending_change": -1,
1796
+ "pending_coin_removal_count": -1,
1797
+ "max_send_amount": 1,
1798
+ },
1799
+ "nft_w_did": {"pending_coin_removal_count": -2, "unspent_coin_count": 1},
1800
+ "nft_no_did": {"pending_coin_removal_count": -1, "unspent_coin_count": -1},
1801
+ },
1802
+ )
1803
+ ]
1804
+ )
1805
+
1806
+ wallet_by_did_response = await env.rpc_client.get_nft_wallet_by_did(NFTGetByDID(did_id=hmr_did_id))
1807
+ assert env.wallet_aliases["nft_w_did"] == wallet_by_did_response.wallet_id
1808
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_w_did"], start_index=0, num=3))["nft_list"]
1809
+ assert len(coins) == 3
1810
+ nft1 = NFTInfo.from_json_dict(coins[0])
1811
+ nft12 = NFTInfo.from_json_dict(coins[1])
1812
+ nft13 = NFTInfo.from_json_dict(coins[2])
1813
+ nft_wallet_to_check = env.wallet_state_manager.wallets[uint32(env.wallet_aliases["nft_w_did"])]
1814
+ assert isinstance(nft_wallet_to_check, NFTWallet)
1815
+ assert await nft_wallet_to_check.get_nft_count() == 3
1816
+
1817
+ assert nft1.owner_did is not None
1818
+ assert nft1.owner_did.hex() == hex_did_id
1819
+ assert nft12.owner_did is not None
1820
+ assert nft12.owner_did.hex() == hex_did_id
1821
+ assert nft13.owner_did is not None
1822
+ assert nft13.owner_did.hex() == hex_did_id
1823
+
1824
+
1825
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
1826
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 2, "blocks_needed": [1, 1]}], indirect=True)
1827
+ @pytest.mark.anyio
1828
+ async def test_nft_bulk_transfer(wallet_environments: WalletTestFramework) -> None:
1829
+ env_0 = wallet_environments.environments[0]
1830
+ env_1 = wallet_environments.environments[1]
1831
+ wallet_0 = env_0.xch_wallet
1832
+ wallet_1 = env_1.xch_wallet
1833
+
1834
+ env_0.wallet_aliases = {
1835
+ "xch": 1,
1836
+ "did": 2,
1837
+ "nft_w_did": 3,
1838
+ "nft_no_did": 4,
1839
+ }
1840
+ env_1.wallet_aliases = {
1841
+ "xch": 1,
1842
+ "nft": 2,
1843
+ }
1844
+ async with env_0.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
1845
+ did_wallet = await DIDWallet.create_new_did_wallet(
1846
+ env_0.wallet_state_manager, wallet_0, uint64(1), action_scope
1847
+ )
1848
+
1849
+ # use "set_remainder" here because this is more of a DID test issue
1850
+ await wallet_environments.process_pending_states(
1851
+ [
1852
+ WalletStateTransition(
1853
+ pre_block_balance_updates={
1854
+ "xch": {"set_remainder": True},
1855
+ "did": {"init": True, "set_remainder": True},
1856
+ },
1857
+ post_block_balance_updates={
1858
+ "xch": {"set_remainder": True},
1859
+ "did": {"set_remainder": True},
1860
+ },
1861
+ ),
1862
+ WalletStateTransition(),
1863
+ ]
1864
+ )
1865
+
1866
+ hex_did_id = did_wallet.get_my_DID()
1867
+ hmr_did_id = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id), AddressType.DID.hrp(env_0.node.config))
1868
+
1869
+ res = await env_0.rpc_client.fetch(
1870
+ "create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1", did_id=hmr_did_id)
1871
+ )
1872
+ assert isinstance(res, dict)
1873
+ assert res.get("success")
1874
+ assert env_0.wallet_aliases["nft_w_did"] == res["wallet_id"]
1875
+ res = await env_0.rpc_client.fetch("create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 2"))
1876
+ assert isinstance(res, dict)
1877
+ assert res.get("success")
1878
+ assert env_0.wallet_aliases["nft_no_did"] == res["wallet_id"]
1879
+
1880
+ await wallet_environments.process_pending_states(
1881
+ [
1882
+ WalletStateTransition(
1883
+ pre_block_balance_updates={
1884
+ "nft_w_did": {"init": True},
1885
+ "nft_no_did": {"init": True},
1886
+ },
1887
+ post_block_balance_updates={},
1888
+ ),
1889
+ WalletStateTransition(),
1890
+ ]
1891
+ )
1892
+
1893
+ # Create an NFT with DID
1894
+ mint_resp_1 = await env_0.rpc_client.mint_nft(
1895
+ wallet_id=env_0.wallet_aliases["nft_w_did"],
1896
+ royalty_address=None,
1897
+ target_address=None, # doesn't matter so we'll just reuse
1898
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1899
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1900
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1901
+ tx_config=wallet_environments.tx_config,
1902
+ did_id=hmr_did_id,
1903
+ )
1904
+ assert len(compute_memos(mint_resp_1.spend_bundle)) > 0
1905
+
1906
+ await wallet_environments.process_pending_states(
1907
+ [
1908
+ WalletStateTransition(
1909
+ pre_block_balance_updates={
1910
+ "xch": {
1911
+ "unconfirmed_wallet_balance": -1,
1912
+ "<=#spendable_balance": -1,
1913
+ ">=#pending_change": 1, # any amount increase
1914
+ "<=#max_send_amount": -1,
1915
+ "pending_coin_removal_count": 1,
1916
+ },
1917
+ "did": {
1918
+ "spendable_balance": -1,
1919
+ "pending_change": 1,
1920
+ "pending_coin_removal_count": 1,
1921
+ "max_send_amount": -1,
1922
+ },
1923
+ "nft_w_did": {"pending_coin_removal_count": 1},
1924
+ },
1925
+ post_block_balance_updates={
1926
+ "xch": {
1927
+ "confirmed_wallet_balance": -1,
1928
+ ">=#spendable_balance": 1, # any amount increase
1929
+ "<=#pending_change": -1, # any amount decrease
1930
+ ">=#max_send_amount": 1, # any amount increase
1931
+ "pending_coin_removal_count": -1,
1932
+ },
1933
+ "did": {
1934
+ "spendable_balance": 1,
1935
+ "pending_change": -1,
1936
+ "pending_coin_removal_count": -1,
1937
+ "max_send_amount": 1,
1938
+ },
1939
+ "nft_w_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1940
+ },
1941
+ )
1942
+ ]
1943
+ )
1944
+
1945
+ # And one w/o
1946
+ mint_resp_2 = await env_0.rpc_client.mint_nft(
1947
+ wallet_id=env_0.wallet_aliases["nft_no_did"],
1948
+ royalty_address=None,
1949
+ target_address=None, # doesn't matter so we'll just reuse
1950
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1951
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1952
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1953
+ tx_config=wallet_environments.tx_config,
1954
+ did_id="",
1955
+ )
1956
+ assert len(compute_memos(mint_resp_2.spend_bundle)) > 0
1957
+
1958
+ await wallet_environments.process_pending_states(
1959
+ [
1960
+ WalletStateTransition(
1961
+ pre_block_balance_updates={
1962
+ "xch": {
1963
+ "unconfirmed_wallet_balance": -1,
1964
+ "<=#spendable_balance": -1,
1965
+ ">=#pending_change": 1, # any amount increase
1966
+ "<=#max_send_amount": -1,
1967
+ "pending_coin_removal_count": 1,
1968
+ },
1969
+ "nft_no_did": {"pending_coin_removal_count": 1},
1970
+ },
1971
+ post_block_balance_updates={
1972
+ "xch": {
1973
+ "confirmed_wallet_balance": -1,
1974
+ ">=#spendable_balance": 1, # any amount increase
1975
+ "<=#pending_change": -1, # any amount decrease
1976
+ ">=#max_send_amount": 1, # any amount increase
1977
+ "pending_coin_removal_count": -1,
1978
+ },
1979
+ "nft_no_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
1980
+ },
1981
+ )
1982
+ ]
1983
+ )
1984
+
1985
+ # Make a second one w/ DID to test "bulk" updating in same wallet
1986
+ mint_resp_3 = await env_0.rpc_client.mint_nft(
1987
+ wallet_id=env_0.wallet_aliases["nft_w_did"],
1988
+ royalty_address=None,
1989
+ target_address=None, # doesn't matter so we'll just reuse
1990
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
1991
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1992
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
1993
+ tx_config=wallet_environments.tx_config,
1994
+ did_id=hmr_did_id,
1995
+ )
1996
+ assert len(compute_memos(mint_resp_3.spend_bundle)) > 0
1997
+
1998
+ await wallet_environments.process_pending_states(
1999
+ [
2000
+ WalletStateTransition(
2001
+ pre_block_balance_updates={
2002
+ "xch": {
2003
+ "unconfirmed_wallet_balance": -1,
2004
+ "<=#spendable_balance": -1,
2005
+ ">=#pending_change": 1, # any amount increase
2006
+ "<=#max_send_amount": -1,
2007
+ "pending_coin_removal_count": 1,
2008
+ },
2009
+ "did": {
2010
+ "spendable_balance": -1,
2011
+ "pending_change": 1,
2012
+ "pending_coin_removal_count": 1,
2013
+ "max_send_amount": -1,
2014
+ },
2015
+ "nft_w_did": {"pending_coin_removal_count": 1},
2016
+ },
2017
+ post_block_balance_updates={
2018
+ "xch": {
2019
+ "confirmed_wallet_balance": -1,
2020
+ ">=#spendable_balance": 1, # any amount increase
2021
+ "<=#pending_change": -1, # any amount decrease
2022
+ ">=#max_send_amount": 1, # any amount increase
2023
+ "pending_coin_removal_count": -1,
2024
+ },
2025
+ "did": {
2026
+ "spendable_balance": 1,
2027
+ "pending_change": -1,
2028
+ "pending_coin_removal_count": -1,
2029
+ "max_send_amount": 1,
2030
+ },
2031
+ "nft_w_did": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
2032
+ },
2033
+ )
2034
+ ]
2035
+ )
2036
+
2037
+ # Check DID NFT
2038
+ coins = (await env_0.rpc_client.list_nfts(env_0.wallet_aliases["nft_w_did"], start_index=0, num=2))["nft_list"]
2039
+ assert len(coins) == 2
2040
+ nft1 = NFTInfo.from_json_dict(coins[0])
2041
+ nft12 = NFTInfo.from_json_dict(coins[1])
2042
+ assert nft1.owner_did is not None
2043
+ assert nft12.owner_did is not None
2044
+ coins = (await env_0.rpc_client.list_nfts(env_0.wallet_aliases["nft_no_did"], start_index=0, num=1))["nft_list"]
2045
+ assert len(coins) == 1
2046
+ nft2 = NFTInfo.from_json_dict(coins[0])
2047
+ assert nft2.owner_did is None
2048
+ nft_coin_list = [
2049
+ NFTCoin(wallet_id=uint32(env_0.wallet_aliases["nft_w_did"]), nft_coin_id=nft1.nft_coin_id.hex()),
2050
+ NFTCoin(wallet_id=uint32(env_0.wallet_aliases["nft_w_did"]), nft_coin_id=nft12.nft_coin_id.hex()),
2051
+ NFTCoin(wallet_id=uint32(env_0.wallet_aliases["nft_no_did"]), nft_coin_id=nft2.nft_coin_id.hex()),
2052
+ ]
2053
+
2054
+ fee = uint64(1000)
2055
+ address = encode_puzzle_hash(await wallet_1.get_puzzle_hash(new=False), AddressType.XCH.hrp(env_1.node.config))
2056
+ bulk_transfer_resp = await env_0.rpc_client.transfer_nft_bulk(
2057
+ NFTTransferBulk(target_address=address, nft_coin_list=nft_coin_list, fee=fee, push=True),
2058
+ wallet_environments.tx_config,
2059
+ )
2060
+ assert len(bulk_transfer_resp.spend_bundle.coin_spends) == 4
2061
+ assert bulk_transfer_resp.tx_num == 4
2062
+
2063
+ await wallet_environments.process_pending_states(
2064
+ [
2065
+ WalletStateTransition(
2066
+ pre_block_balance_updates={
2067
+ "xch": {
2068
+ "unconfirmed_wallet_balance": -fee,
2069
+ "<=#spendable_balance": -fee,
2070
+ ">=#pending_change": 1, # any amount increase
2071
+ "<=#max_send_amount": -fee,
2072
+ "pending_coin_removal_count": 1,
2073
+ },
2074
+ "did": {},
2075
+ "nft_w_did": {"pending_coin_removal_count": 2},
2076
+ "nft_no_did": {"pending_coin_removal_count": 1},
2077
+ },
2078
+ post_block_balance_updates={
2079
+ "xch": {
2080
+ "confirmed_wallet_balance": -fee,
2081
+ ">=#spendable_balance": 1, # any amount increase
2082
+ "<=#pending_change": -1, # any amount decrease
2083
+ ">=#max_send_amount": 1, # any amount increase
2084
+ "pending_coin_removal_count": -1,
2085
+ },
2086
+ "did": {},
2087
+ "nft_w_did": {"pending_coin_removal_count": -2, "unspent_coin_count": -2},
2088
+ "nft_no_did": {"pending_coin_removal_count": -1, "unspent_coin_count": -1},
2089
+ },
2090
+ ),
2091
+ WalletStateTransition(
2092
+ pre_block_balance_updates={
2093
+ "xch": {},
2094
+ },
2095
+ post_block_balance_updates={
2096
+ "xch": {},
2097
+ "nft": {"init": True, "unspent_coin_count": 3},
2098
+ },
2099
+ ),
2100
+ ]
2101
+ )
2102
+
2103
+ await time_out_assert(30, get_wallet_number, 2, env_1.wallet_state_manager)
2104
+ coins = (await env_1.rpc_client.list_nfts(env_1.wallet_aliases["nft"], start_index=0, num=3))["nft_list"]
2105
+ assert len(coins) == 3
2106
+ nft0 = NFTInfo.from_json_dict(coins[0])
2107
+ nft02 = NFTInfo.from_json_dict(coins[1])
2108
+ nft03 = NFTInfo.from_json_dict(coins[2])
2109
+ nft_set = {nft1.launcher_id, nft12.launcher_id, nft2.launcher_id}
2110
+ assert nft0.launcher_id in nft_set
2111
+ assert nft02.launcher_id in nft_set
2112
+ assert nft03.launcher_id in nft_set
2113
+ assert nft0.owner_did is None
2114
+ assert nft02.owner_did is None
2115
+ assert nft03.owner_did is None
2116
+
2117
+
2118
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
2119
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
2120
+ @pytest.mark.anyio
2121
+ async def test_nft_set_did(wallet_environments: WalletTestFramework) -> None:
2122
+ env = wallet_environments.environments[0]
2123
+ wallet = env.xch_wallet
2124
+
2125
+ env.wallet_aliases = {
2126
+ "xch": 1,
2127
+ "did1": 2,
2128
+ "nft_w_did1": 3,
2129
+ "nft_no_did": 4,
2130
+ "did2": 5,
2131
+ "nft_w_did2": 6,
2132
+ }
2133
+
2134
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2135
+ did_wallet = await DIDWallet.create_new_did_wallet(env.wallet_state_manager, wallet, uint64(1), action_scope)
2136
+
2137
+ # use "set_remainder" here because this is more of a DID test issue
2138
+ await wallet_environments.process_pending_states(
2139
+ [
2140
+ WalletStateTransition(
2141
+ pre_block_balance_updates={
2142
+ "xch": {"set_remainder": True},
2143
+ "did1": {"init": True, "set_remainder": True},
2144
+ },
2145
+ post_block_balance_updates={
2146
+ "xch": {"set_remainder": True},
2147
+ "did1": {"set_remainder": True},
2148
+ },
2149
+ )
2150
+ ]
2151
+ )
2152
+
2153
+ hex_did_id = did_wallet.get_my_DID()
2154
+ hmr_did_id = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id), AddressType.DID.hrp(env.node.config))
2155
+
2156
+ res = await env.rpc_client.fetch(
2157
+ "create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1", did_id=hmr_did_id)
2158
+ )
2159
+ assert isinstance(res, dict)
2160
+ assert res.get("success")
2161
+ assert env.wallet_aliases["nft_w_did1"] == res["wallet_id"]
2162
+
2163
+ await wallet_environments.process_pending_states(
2164
+ [WalletStateTransition(pre_block_balance_updates={"nft_w_did1": {"init": True}})]
2165
+ )
2166
+
2167
+ mint_resp = await env.rpc_client.mint_nft(
2168
+ wallet_id=env.wallet_aliases["nft_w_did1"],
2169
+ royalty_address=None,
2170
+ target_address=None, # doesn't matter so we'll just reuse
2171
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
2172
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
2173
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
2174
+ tx_config=wallet_environments.tx_config,
2175
+ did_id="",
2176
+ )
2177
+ assert len(compute_memos(mint_resp.spend_bundle)) > 0
2178
+
2179
+ await wallet_environments.process_pending_states(
2180
+ [
2181
+ WalletStateTransition(
2182
+ pre_block_balance_updates={
2183
+ "xch": {
2184
+ "unconfirmed_wallet_balance": -1,
2185
+ "<=#spendable_balance": -1,
2186
+ ">=#pending_change": 1, # any amount increase
2187
+ "<=#max_send_amount": -1,
2188
+ "pending_coin_removal_count": 1,
2189
+ },
2190
+ "nft_w_did1": {"pending_coin_removal_count": 1},
2191
+ },
2192
+ post_block_balance_updates={
2193
+ "xch": {
2194
+ "confirmed_wallet_balance": -1,
2195
+ ">=#spendable_balance": 1, # any amount increase
2196
+ "<=#pending_change": -1, # any amount decrease
2197
+ ">=#max_send_amount": 1, # any amount increase
2198
+ "pending_coin_removal_count": -1,
2199
+ },
2200
+ "nft_w_did1": {"pending_coin_removal_count": -1},
2201
+ "nft_no_did": {"init": True, "unspent_coin_count": 1},
2202
+ },
2203
+ )
2204
+ ]
2205
+ )
2206
+
2207
+ # Check DID NFT
2208
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_no_did"], start_index=0, num=1))["nft_list"]
2209
+ assert len(coins) == 1
2210
+ coin = NFTInfo.from_json_dict(coins[0])
2211
+ assert coin.owner_did is None
2212
+ nft_coin_id = coin.nft_coin_id
2213
+
2214
+ # Test set None -> DID1
2215
+ async with env.wallet_state_manager.new_action_scope(wallet_environments.tx_config, push=True) as action_scope:
2216
+ did_wallet2 = await DIDWallet.create_new_did_wallet(env.wallet_state_manager, wallet, uint64(1), action_scope)
2217
+
2218
+ # use "set_remainder" here because this is more of a DID test issue
2219
+ await wallet_environments.process_pending_states(
2220
+ [
2221
+ WalletStateTransition(
2222
+ pre_block_balance_updates={
2223
+ "xch": {"set_remainder": True},
2224
+ "did2": {"init": True, "set_remainder": True},
2225
+ },
2226
+ post_block_balance_updates={
2227
+ "xch": {"set_remainder": True},
2228
+ "did2": {"set_remainder": True},
2229
+ },
2230
+ )
2231
+ ]
2232
+ )
2233
+
2234
+ await env.rpc_client.set_nft_did(
2235
+ wallet_id=env.wallet_aliases["nft_no_did"],
2236
+ did_id=hmr_did_id,
2237
+ nft_coin_id=nft_coin_id.hex(),
2238
+ tx_config=wallet_environments.tx_config,
2239
+ fee=0,
2240
+ )
2241
+
2242
+ await wallet_environments.process_pending_states(
2243
+ [
2244
+ WalletStateTransition(
2245
+ pre_block_balance_updates={
2246
+ "xch": {},
2247
+ "did1": {
2248
+ "spendable_balance": -1,
2249
+ "pending_change": 1,
2250
+ "pending_coin_removal_count": 1,
2251
+ "max_send_amount": -1,
2252
+ },
2253
+ "nft_no_did": {"pending_coin_removal_count": 1},
2254
+ },
2255
+ post_block_balance_updates={
2256
+ "xch": {},
2257
+ "did1": {
2258
+ "spendable_balance": 1,
2259
+ "pending_change": -1,
2260
+ "pending_coin_removal_count": -1,
2261
+ "max_send_amount": 1,
2262
+ },
2263
+ "nft_no_did": {"pending_coin_removal_count": -1, "unspent_coin_count": -1},
2264
+ "nft_w_did1": {"unspent_coin_count": 1},
2265
+ },
2266
+ )
2267
+ ]
2268
+ )
2269
+
2270
+ nft_wallet_to_check = env.wallet_state_manager.wallets[uint32(env.wallet_aliases["nft_no_did"])]
2271
+ assert isinstance(nft_wallet_to_check, NFTWallet)
2272
+ assert len(await nft_wallet_to_check.get_current_nfts()) == 0
2273
+
2274
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_w_did1"], start_index=0, num=1))["nft_list"]
2275
+ assert len(coins) == 1
2276
+ coin = NFTInfo.from_json_dict(coins[0])
2277
+ assert coin.owner_did is not None
2278
+ assert coin.owner_did.hex() == hex_did_id
2279
+ nft_coin_id = coin.nft_coin_id
2280
+
2281
+ res = await env.rpc_client.get_nft_info(coin_id=nft_coin_id.hex(), latest=True)
2282
+ assert res["success"]
2283
+ assert coins[0] == res["nft_info"]
2284
+
2285
+ # Test set DID1 -> DID2
2286
+ hex_did_id2 = did_wallet2.get_my_DID()
2287
+ hmr_did_id2 = encode_puzzle_hash(bytes32.from_hexstr(hex_did_id2), AddressType.DID.hrp(env.node.config))
2288
+ await env.rpc_client.set_nft_did(
2289
+ wallet_id=env.wallet_aliases["nft_w_did1"],
2290
+ did_id=hmr_did_id2,
2291
+ nft_coin_id=nft_coin_id.hex(),
2292
+ tx_config=wallet_environments.tx_config,
2293
+ fee=0,
2294
+ )
2295
+
2296
+ await wallet_environments.process_pending_states(
2297
+ [
2298
+ WalletStateTransition(
2299
+ pre_block_balance_updates={
2300
+ "xch": {},
2301
+ "did2": {
2302
+ "spendable_balance": -1,
2303
+ "pending_change": 1,
2304
+ "pending_coin_removal_count": 1,
2305
+ "max_send_amount": -1,
2306
+ },
2307
+ "nft_w_did1": {"pending_coin_removal_count": 1},
2308
+ },
2309
+ post_block_balance_updates={
2310
+ "xch": {},
2311
+ "did2": {
2312
+ "spendable_balance": 1,
2313
+ "pending_change": -1,
2314
+ "pending_coin_removal_count": -1,
2315
+ "max_send_amount": 1,
2316
+ },
2317
+ "nft_w_did1": {"pending_coin_removal_count": -1, "unspent_coin_count": -1},
2318
+ "nft_w_did2": {"init": True, "unspent_coin_count": 1},
2319
+ },
2320
+ )
2321
+ ]
2322
+ )
2323
+
2324
+ # Check NFT DID
2325
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_w_did2"], start_index=0, num=1))["nft_list"]
2326
+ assert len(coins) == 1
2327
+ coin = NFTInfo.from_json_dict(coins[0])
2328
+ assert coin.owner_did is not None
2329
+ assert coin.owner_did.hex() == hex_did_id2
2330
+ nft_coin_id = coin.nft_coin_id
2331
+ res = await env.rpc_client.get_nft_info(coin_id=nft_coin_id.hex(), latest=True)
2332
+ assert res["success"]
2333
+ assert coins[0] == res["nft_info"]
2334
+
2335
+ # Test set DID2 -> None
2336
+ await env.rpc_client.set_nft_did(
2337
+ wallet_id=env.wallet_aliases["nft_w_did2"],
2338
+ did_id=None,
2339
+ nft_coin_id=nft_coin_id.hex(),
2340
+ tx_config=wallet_environments.tx_config,
2341
+ fee=0,
2342
+ )
2343
+
2344
+ await wallet_environments.process_pending_states(
2345
+ [
2346
+ WalletStateTransition(
2347
+ pre_block_balance_updates={
2348
+ "xch": {},
2349
+ "nft_w_did2": {"pending_coin_removal_count": 1},
2350
+ },
2351
+ post_block_balance_updates={
2352
+ "xch": {},
2353
+ "nft_w_did2": {"pending_coin_removal_count": -1, "unspent_coin_count": -1},
2354
+ "nft_no_did": {"unspent_coin_count": 1},
2355
+ },
2356
+ )
2357
+ ]
2358
+ )
2359
+
2360
+ # Check NFT DID
2361
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft_no_did"], start_index=0, num=1))["nft_list"]
2362
+ assert len(coins) == 1
2363
+ coin = NFTInfo.from_json_dict(coins[0])
2364
+ assert coin.owner_did is None
2365
+ res = await env.rpc_client.get_nft_info(coin_id=nft_coin_id.hex(), latest=True)
2366
+ assert res["success"]
2367
+ assert coins[0] == res["nft_info"]
2368
+
2369
+
2370
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
2371
+ @pytest.mark.parametrize("wallet_environments", [{"num_environments": 1, "blocks_needed": [1]}], indirect=True)
2372
+ @pytest.mark.anyio
2373
+ async def test_set_nft_status(wallet_environments: WalletTestFramework) -> None:
2374
+ env = wallet_environments.environments[0]
2375
+
2376
+ env.wallet_aliases = {
2377
+ "xch": 1,
2378
+ "nft": 2,
2379
+ }
2380
+
2381
+ res = await env.rpc_client.fetch("create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1"))
2382
+ assert isinstance(res, dict)
2383
+ assert res.get("success")
2384
+
2385
+ await wallet_environments.process_pending_states(
2386
+ [
2387
+ WalletStateTransition(
2388
+ pre_block_balance_updates={
2389
+ "xch": {},
2390
+ "nft": {"init": True},
2391
+ },
2392
+ post_block_balance_updates={
2393
+ "xch": {},
2394
+ "nft": {},
2395
+ },
2396
+ )
2397
+ ]
2398
+ )
2399
+
2400
+ # Create a NFT without DID
2401
+ await env.rpc_client.mint_nft(
2402
+ wallet_id=env.wallet_aliases["nft"],
2403
+ royalty_address=None,
2404
+ target_address=None, # doesn't matter so we'll just reuse
2405
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
2406
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
2407
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
2408
+ tx_config=wallet_environments.tx_config,
2409
+ did_id="",
2410
+ )
2411
+
2412
+ await wallet_environments.process_pending_states(
2413
+ [
2414
+ WalletStateTransition(
2415
+ pre_block_balance_updates={
2416
+ "xch": {
2417
+ "unconfirmed_wallet_balance": -1,
2418
+ "<=#spendable_balance": -1,
2419
+ ">=#pending_change": 1, # any amount increase
2420
+ "<=#max_send_amount": -1,
2421
+ "pending_coin_removal_count": 1,
2422
+ },
2423
+ "nft": {"init": True, "pending_coin_removal_count": 1},
2424
+ },
2425
+ post_block_balance_updates={
2426
+ "xch": {
2427
+ "confirmed_wallet_balance": -1,
2428
+ ">=#spendable_balance": 1, # any amount increase
2429
+ "<=#pending_change": -1, # any amount decrease
2430
+ ">=#max_send_amount": 1, # any amount increase
2431
+ "pending_coin_removal_count": -1,
2432
+ },
2433
+ "nft": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
2434
+ },
2435
+ )
2436
+ ]
2437
+ )
2438
+
2439
+ # Check DID NFT
2440
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft"], start_index=0, num=1))["nft_list"]
2441
+ assert len(coins) == 1
2442
+ coin = NFTInfo.from_json_dict(coins[0])
2443
+ assert coin.owner_did is None
2444
+ assert not coin.pending_transaction
2445
+ nft_coin_id = coin.nft_coin_id
2446
+ # Set status
2447
+ await env.rpc_client.set_nft_status(
2448
+ NFTSetNFTStatus(wallet_id=uint32(env.wallet_aliases["nft"]), coin_id=nft_coin_id, in_transaction=True)
2449
+ )
2450
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft"], start_index=0, num=1))["nft_list"]
2451
+ assert len(coins) == 1
2452
+ coin = NFTInfo.from_json_dict(coins[0])
2453
+ assert coin.pending_transaction
2454
+
2455
+
2456
+ @pytest.mark.limit_consensus_modes(allowed=[ConsensusMode.PLAIN], reason="irrelevant")
2457
+ @pytest.mark.parametrize(
2458
+ "wallet_environments",
2459
+ [{"num_environments": 1, "blocks_needed": [1], "reuse_puzhash": True, "trusted": True}],
2460
+ indirect=True,
2461
+ )
2462
+ @pytest.mark.anyio
2463
+ async def test_nft_sign_message(wallet_environments: WalletTestFramework) -> None:
2464
+ env = wallet_environments.environments[0]
2465
+
2466
+ env.wallet_aliases = {
2467
+ "xch": 1,
2468
+ "nft": 2,
2469
+ }
2470
+
2471
+ res = await env.rpc_client.fetch("create_new_wallet", dict(wallet_type="nft_wallet", name="NFT WALLET 1"))
2472
+ assert isinstance(res, dict)
2473
+ assert res.get("success")
2474
+
2475
+ await wallet_environments.process_pending_states(
2476
+ [
2477
+ WalletStateTransition(
2478
+ pre_block_balance_updates={
2479
+ "xch": {},
2480
+ "nft": {"init": True},
2481
+ },
2482
+ post_block_balance_updates={
2483
+ "xch": {},
2484
+ "nft": {},
2485
+ },
2486
+ )
2487
+ ]
2488
+ )
2489
+
2490
+ # Create a NFT without DID
2491
+ await env.rpc_client.mint_nft(
2492
+ wallet_id=env.wallet_aliases["nft"],
2493
+ royalty_address=None,
2494
+ target_address=None, # doesn't matter so we'll just reuse
2495
+ hash="0xD4584AD463139FA8C0D9F68F4B59F185",
2496
+ uris=["https://www.chia.net/img/branding/chia-logo.svg"],
2497
+ meta_uris=["https://www.chia.net/img/branding/chia-logo.svg"],
2498
+ tx_config=wallet_environments.tx_config,
2499
+ did_id="",
2500
+ )
2501
+
2502
+ await wallet_environments.process_pending_states(
2503
+ [
2504
+ WalletStateTransition(
2505
+ pre_block_balance_updates={
2506
+ "xch": {
2507
+ "unconfirmed_wallet_balance": -1,
2508
+ "<=#spendable_balance": -1,
2509
+ ">=#pending_change": 1, # any amount increase
2510
+ "<=#max_send_amount": -1,
2511
+ "pending_coin_removal_count": 1,
2512
+ },
2513
+ "nft": {"init": True, "pending_coin_removal_count": 1},
2514
+ },
2515
+ post_block_balance_updates={
2516
+ "xch": {
2517
+ "confirmed_wallet_balance": -1,
2518
+ ">=#spendable_balance": 1, # any amount increase
2519
+ "<=#pending_change": -1, # any amount decrease
2520
+ ">=#max_send_amount": 1, # any amount increase
2521
+ "pending_coin_removal_count": -1,
2522
+ },
2523
+ "nft": {"pending_coin_removal_count": -1, "unspent_coin_count": 1},
2524
+ },
2525
+ )
2526
+ ]
2527
+ )
2528
+
2529
+ # Check DID NFT
2530
+ coins = (await env.rpc_client.list_nfts(env.wallet_aliases["nft"], start_index=0, num=1))["nft_list"]
2531
+ assert len(coins) == 1
2532
+ coin = NFTInfo.from_json_dict(coins[0])
2533
+ assert coin.owner_did is None
2534
+ assert not coin.pending_transaction
2535
+ # Test general string
2536
+ message = "Hello World"
2537
+ pubkey, sig, _ = await env.rpc_client.sign_message_by_id(
2538
+ id=encode_puzzle_hash(coin.launcher_id, AddressType.NFT.value), message=message
2539
+ )
2540
+ puzzle = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, message))
2541
+ assert AugSchemeMPL.verify(
2542
+ G1Element.from_bytes(bytes.fromhex(pubkey)),
2543
+ puzzle.get_tree_hash(),
2544
+ G2Element.from_bytes(bytes.fromhex(sig)),
2545
+ )
2546
+ # Test hex string
2547
+ message = "0123456789ABCDEF"
2548
+ pubkey, sig, _ = await env.rpc_client.sign_message_by_id(
2549
+ id=encode_puzzle_hash(coin.launcher_id, AddressType.NFT.value), message=message, is_hex=True
2550
+ )
2551
+ puzzle = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, bytes.fromhex(message)))
2552
+ assert AugSchemeMPL.verify(
2553
+ G1Element.from_bytes(bytes.fromhex(pubkey)),
2554
+ puzzle.get_tree_hash(),
2555
+ G2Element.from_bytes(bytes.fromhex(sig)),
2556
+ )
2557
+ # Test BLS sign string
2558
+ message = "Hello World"
2559
+ pubkey, sig, _ = await env.rpc_client.sign_message_by_id(
2560
+ id=encode_puzzle_hash(coin.launcher_id, AddressType.NFT.value),
2561
+ message=message,
2562
+ is_hex=False,
2563
+ safe_mode=False,
2564
+ )
2565
+
2566
+ assert AugSchemeMPL.verify(
2567
+ G1Element.from_bytes(bytes.fromhex(pubkey)),
2568
+ bytes(message, "utf-8"),
2569
+ G2Element.from_bytes(bytes.fromhex(sig)),
2570
+ )
2571
+ # Test BLS sign hex
2572
+ message = "0123456789ABCDEF"
2573
+ pubkey, sig, _ = await env.rpc_client.sign_message_by_id(
2574
+ id=encode_puzzle_hash(coin.launcher_id, AddressType.NFT.value),
2575
+ message=message,
2576
+ is_hex=True,
2577
+ safe_mode=False,
2578
+ )
2579
+
2580
+ assert AugSchemeMPL.verify(
2581
+ G1Element.from_bytes(bytes.fromhex(pubkey)),
2582
+ bytes.fromhex(message),
2583
+ G2Element.from_bytes(bytes.fromhex(sig)),
2584
+ )