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