chia-blockchain 2.5.1rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1042) hide show
  1. chia/__init__.py +10 -0
  2. chia/__main__.py +5 -0
  3. chia/_tests/README.md +53 -0
  4. chia/_tests/__init__.py +0 -0
  5. chia/_tests/blockchain/__init__.py +0 -0
  6. chia/_tests/blockchain/blockchain_test_utils.py +195 -0
  7. chia/_tests/blockchain/config.py +4 -0
  8. chia/_tests/blockchain/test_augmented_chain.py +145 -0
  9. chia/_tests/blockchain/test_blockchain.py +4202 -0
  10. chia/_tests/blockchain/test_blockchain_transactions.py +1031 -0
  11. chia/_tests/blockchain/test_build_chains.py +59 -0
  12. chia/_tests/blockchain/test_get_block_generator.py +72 -0
  13. chia/_tests/blockchain/test_lookup_fork_chain.py +194 -0
  14. chia/_tests/build-init-files.py +92 -0
  15. chia/_tests/build-job-matrix.py +204 -0
  16. chia/_tests/check_pytest_monitor_output.py +34 -0
  17. chia/_tests/check_sql_statements.py +72 -0
  18. chia/_tests/chia-start-sim +42 -0
  19. chia/_tests/clvm/__init__.py +0 -0
  20. chia/_tests/clvm/benchmark_costs.py +23 -0
  21. chia/_tests/clvm/coin_store.py +149 -0
  22. chia/_tests/clvm/test_chialisp_deserialization.py +101 -0
  23. chia/_tests/clvm/test_clvm_step.py +37 -0
  24. chia/_tests/clvm/test_condition_codes.py +13 -0
  25. chia/_tests/clvm/test_curry_and_treehash.py +55 -0
  26. chia/_tests/clvm/test_message_conditions.py +184 -0
  27. chia/_tests/clvm/test_program.py +150 -0
  28. chia/_tests/clvm/test_puzzle_compression.py +143 -0
  29. chia/_tests/clvm/test_puzzle_drivers.py +45 -0
  30. chia/_tests/clvm/test_puzzles.py +242 -0
  31. chia/_tests/clvm/test_singletons.py +540 -0
  32. chia/_tests/clvm/test_spend_sim.py +181 -0
  33. chia/_tests/cmds/__init__.py +0 -0
  34. chia/_tests/cmds/cmd_test_utils.py +469 -0
  35. chia/_tests/cmds/config.py +3 -0
  36. chia/_tests/cmds/conftest.py +23 -0
  37. chia/_tests/cmds/test_click_types.py +200 -0
  38. chia/_tests/cmds/test_cmd_framework.py +620 -0
  39. chia/_tests/cmds/test_cmds_util.py +97 -0
  40. chia/_tests/cmds/test_daemon.py +92 -0
  41. chia/_tests/cmds/test_dev_gh.py +131 -0
  42. chia/_tests/cmds/test_farm_cmd.py +66 -0
  43. chia/_tests/cmds/test_show.py +116 -0
  44. chia/_tests/cmds/test_sim.py +207 -0
  45. chia/_tests/cmds/test_timelock_args.py +75 -0
  46. chia/_tests/cmds/test_tx_config_args.py +154 -0
  47. chia/_tests/cmds/testing_classes.py +59 -0
  48. chia/_tests/cmds/wallet/__init__.py +0 -0
  49. chia/_tests/cmds/wallet/test_consts.py +47 -0
  50. chia/_tests/cmds/wallet/test_dao.py +565 -0
  51. chia/_tests/cmds/wallet/test_did.py +403 -0
  52. chia/_tests/cmds/wallet/test_nft.py +471 -0
  53. chia/_tests/cmds/wallet/test_notifications.py +124 -0
  54. chia/_tests/cmds/wallet/test_offer.toffer +1 -0
  55. chia/_tests/cmds/wallet/test_tx_decorators.py +27 -0
  56. chia/_tests/cmds/wallet/test_vcs.py +400 -0
  57. chia/_tests/cmds/wallet/test_wallet.py +1125 -0
  58. chia/_tests/cmds/wallet/test_wallet_check.py +109 -0
  59. chia/_tests/conftest.py +1419 -0
  60. chia/_tests/connection_utils.py +125 -0
  61. chia/_tests/core/__init__.py +0 -0
  62. chia/_tests/core/cmds/__init__.py +0 -0
  63. chia/_tests/core/cmds/test_beta.py +382 -0
  64. chia/_tests/core/cmds/test_keys.py +1734 -0
  65. chia/_tests/core/cmds/test_wallet.py +126 -0
  66. chia/_tests/core/config.py +3 -0
  67. chia/_tests/core/consensus/__init__.py +0 -0
  68. chia/_tests/core/consensus/test_block_creation.py +54 -0
  69. chia/_tests/core/consensus/test_pot_iterations.py +117 -0
  70. chia/_tests/core/custom_types/__init__.py +0 -0
  71. chia/_tests/core/custom_types/test_coin.py +107 -0
  72. chia/_tests/core/custom_types/test_proof_of_space.py +144 -0
  73. chia/_tests/core/custom_types/test_spend_bundle.py +70 -0
  74. chia/_tests/core/daemon/__init__.py +0 -0
  75. chia/_tests/core/daemon/config.py +4 -0
  76. chia/_tests/core/daemon/test_daemon.py +2128 -0
  77. chia/_tests/core/daemon/test_daemon_register.py +109 -0
  78. chia/_tests/core/daemon/test_keychain_proxy.py +101 -0
  79. chia/_tests/core/data_layer/__init__.py +0 -0
  80. chia/_tests/core/data_layer/config.py +5 -0
  81. chia/_tests/core/data_layer/conftest.py +106 -0
  82. chia/_tests/core/data_layer/test_data_cli.py +56 -0
  83. chia/_tests/core/data_layer/test_data_layer.py +83 -0
  84. chia/_tests/core/data_layer/test_data_layer_util.py +218 -0
  85. chia/_tests/core/data_layer/test_data_rpc.py +3847 -0
  86. chia/_tests/core/data_layer/test_data_store.py +2424 -0
  87. chia/_tests/core/data_layer/test_data_store_schema.py +381 -0
  88. chia/_tests/core/data_layer/test_plugin.py +91 -0
  89. chia/_tests/core/data_layer/util.py +233 -0
  90. chia/_tests/core/farmer/__init__.py +0 -0
  91. chia/_tests/core/farmer/config.py +3 -0
  92. chia/_tests/core/farmer/test_farmer_api.py +103 -0
  93. chia/_tests/core/full_node/__init__.py +0 -0
  94. chia/_tests/core/full_node/config.py +4 -0
  95. chia/_tests/core/full_node/dos/__init__.py +0 -0
  96. chia/_tests/core/full_node/dos/config.py +3 -0
  97. chia/_tests/core/full_node/full_sync/__init__.py +0 -0
  98. chia/_tests/core/full_node/full_sync/config.py +4 -0
  99. chia/_tests/core/full_node/full_sync/test_full_sync.py +443 -0
  100. chia/_tests/core/full_node/ram_db.py +27 -0
  101. chia/_tests/core/full_node/stores/__init__.py +0 -0
  102. chia/_tests/core/full_node/stores/config.py +4 -0
  103. chia/_tests/core/full_node/stores/test_block_store.py +590 -0
  104. chia/_tests/core/full_node/stores/test_coin_store.py +897 -0
  105. chia/_tests/core/full_node/stores/test_full_node_store.py +1219 -0
  106. chia/_tests/core/full_node/stores/test_hint_store.py +229 -0
  107. chia/_tests/core/full_node/stores/test_sync_store.py +135 -0
  108. chia/_tests/core/full_node/test_address_manager.py +588 -0
  109. chia/_tests/core/full_node/test_block_height_map.py +556 -0
  110. chia/_tests/core/full_node/test_conditions.py +556 -0
  111. chia/_tests/core/full_node/test_full_node.py +2700 -0
  112. chia/_tests/core/full_node/test_generator_tools.py +82 -0
  113. chia/_tests/core/full_node/test_hint_management.py +104 -0
  114. chia/_tests/core/full_node/test_node_load.py +34 -0
  115. chia/_tests/core/full_node/test_performance.py +179 -0
  116. chia/_tests/core/full_node/test_subscriptions.py +492 -0
  117. chia/_tests/core/full_node/test_transactions.py +203 -0
  118. chia/_tests/core/full_node/test_tx_processing_queue.py +155 -0
  119. chia/_tests/core/large_block.py +2388 -0
  120. chia/_tests/core/make_block_generator.py +70 -0
  121. chia/_tests/core/mempool/__init__.py +0 -0
  122. chia/_tests/core/mempool/config.py +4 -0
  123. chia/_tests/core/mempool/test_mempool.py +3255 -0
  124. chia/_tests/core/mempool/test_mempool_fee_estimator.py +104 -0
  125. chia/_tests/core/mempool/test_mempool_fee_protocol.py +55 -0
  126. chia/_tests/core/mempool/test_mempool_item_queries.py +190 -0
  127. chia/_tests/core/mempool/test_mempool_manager.py +2084 -0
  128. chia/_tests/core/mempool/test_mempool_performance.py +64 -0
  129. chia/_tests/core/mempool/test_singleton_fast_forward.py +567 -0
  130. chia/_tests/core/node_height.py +28 -0
  131. chia/_tests/core/server/__init__.py +0 -0
  132. chia/_tests/core/server/config.py +3 -0
  133. chia/_tests/core/server/flood.py +84 -0
  134. chia/_tests/core/server/serve.py +135 -0
  135. chia/_tests/core/server/test_api_protocol.py +21 -0
  136. chia/_tests/core/server/test_capabilities.py +66 -0
  137. chia/_tests/core/server/test_dos.py +319 -0
  138. chia/_tests/core/server/test_event_loop.py +109 -0
  139. chia/_tests/core/server/test_loop.py +294 -0
  140. chia/_tests/core/server/test_node_discovery.py +73 -0
  141. chia/_tests/core/server/test_rate_limits.py +482 -0
  142. chia/_tests/core/server/test_server.py +226 -0
  143. chia/_tests/core/server/test_upnp.py +8 -0
  144. chia/_tests/core/services/__init__.py +0 -0
  145. chia/_tests/core/services/config.py +3 -0
  146. chia/_tests/core/services/test_services.py +188 -0
  147. chia/_tests/core/ssl/__init__.py +0 -0
  148. chia/_tests/core/ssl/config.py +3 -0
  149. chia/_tests/core/ssl/test_ssl.py +202 -0
  150. chia/_tests/core/test_coins.py +33 -0
  151. chia/_tests/core/test_cost_calculation.py +313 -0
  152. chia/_tests/core/test_crawler.py +175 -0
  153. chia/_tests/core/test_crawler_rpc.py +53 -0
  154. chia/_tests/core/test_daemon_rpc.py +24 -0
  155. chia/_tests/core/test_db_conversion.py +130 -0
  156. chia/_tests/core/test_db_validation.py +162 -0
  157. chia/_tests/core/test_farmer_harvester_rpc.py +505 -0
  158. chia/_tests/core/test_filter.py +35 -0
  159. chia/_tests/core/test_full_node_rpc.py +768 -0
  160. chia/_tests/core/test_merkle_set.py +343 -0
  161. chia/_tests/core/test_program.py +47 -0
  162. chia/_tests/core/test_rpc_util.py +86 -0
  163. chia/_tests/core/test_seeder.py +420 -0
  164. chia/_tests/core/test_setproctitle.py +13 -0
  165. chia/_tests/core/util/__init__.py +0 -0
  166. chia/_tests/core/util/config.py +4 -0
  167. chia/_tests/core/util/test_block_cache.py +44 -0
  168. chia/_tests/core/util/test_cached_bls.py +57 -0
  169. chia/_tests/core/util/test_config.py +337 -0
  170. chia/_tests/core/util/test_file_keyring_synchronization.py +105 -0
  171. chia/_tests/core/util/test_files.py +391 -0
  172. chia/_tests/core/util/test_jsonify.py +146 -0
  173. chia/_tests/core/util/test_keychain.py +522 -0
  174. chia/_tests/core/util/test_keyring_wrapper.py +491 -0
  175. chia/_tests/core/util/test_lockfile.py +380 -0
  176. chia/_tests/core/util/test_log_exceptions.py +187 -0
  177. chia/_tests/core/util/test_lru_cache.py +56 -0
  178. chia/_tests/core/util/test_significant_bits.py +40 -0
  179. chia/_tests/core/util/test_streamable.py +883 -0
  180. chia/_tests/db/__init__.py +0 -0
  181. chia/_tests/db/test_db_wrapper.py +566 -0
  182. chia/_tests/environments/__init__.py +0 -0
  183. chia/_tests/environments/common.py +35 -0
  184. chia/_tests/environments/full_node.py +47 -0
  185. chia/_tests/environments/wallet.py +429 -0
  186. chia/_tests/ether.py +19 -0
  187. chia/_tests/farmer_harvester/__init__.py +0 -0
  188. chia/_tests/farmer_harvester/config.py +3 -0
  189. chia/_tests/farmer_harvester/test_farmer.py +1264 -0
  190. chia/_tests/farmer_harvester/test_farmer_harvester.py +292 -0
  191. chia/_tests/farmer_harvester/test_filter_prefix_bits.py +131 -0
  192. chia/_tests/farmer_harvester/test_third_party_harvesters.py +528 -0
  193. chia/_tests/farmer_harvester/test_third_party_harvesters_data.json +29 -0
  194. chia/_tests/fee_estimation/__init__.py +0 -0
  195. chia/_tests/fee_estimation/config.py +3 -0
  196. chia/_tests/fee_estimation/test_fee_estimation_integration.py +262 -0
  197. chia/_tests/fee_estimation/test_fee_estimation_rpc.py +287 -0
  198. chia/_tests/fee_estimation/test_fee_estimation_unit_tests.py +144 -0
  199. chia/_tests/fee_estimation/test_mempoolitem_height_added.py +146 -0
  200. chia/_tests/generator/__init__.py +0 -0
  201. chia/_tests/generator/puzzles/__init__.py +0 -0
  202. chia/_tests/generator/puzzles/test_generator_deserialize.clsp +3 -0
  203. chia/_tests/generator/puzzles/test_generator_deserialize.clsp.hex +1 -0
  204. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp +19 -0
  205. chia/_tests/generator/puzzles/test_multiple_generator_input_arguments.clsp.hex +1 -0
  206. chia/_tests/generator/test_compression.py +201 -0
  207. chia/_tests/generator/test_generator_types.py +44 -0
  208. chia/_tests/generator/test_rom.py +180 -0
  209. chia/_tests/plot_sync/__init__.py +0 -0
  210. chia/_tests/plot_sync/config.py +3 -0
  211. chia/_tests/plot_sync/test_delta.py +101 -0
  212. chia/_tests/plot_sync/test_plot_sync.py +618 -0
  213. chia/_tests/plot_sync/test_receiver.py +451 -0
  214. chia/_tests/plot_sync/test_sender.py +116 -0
  215. chia/_tests/plot_sync/test_sync_simulated.py +451 -0
  216. chia/_tests/plot_sync/util.py +68 -0
  217. chia/_tests/plotting/__init__.py +0 -0
  218. chia/_tests/plotting/config.py +3 -0
  219. chia/_tests/plotting/test_plot_manager.py +781 -0
  220. chia/_tests/plotting/util.py +12 -0
  221. chia/_tests/pools/__init__.py +0 -0
  222. chia/_tests/pools/config.py +5 -0
  223. chia/_tests/pools/test_pool_cli_parsing.py +128 -0
  224. chia/_tests/pools/test_pool_cmdline.py +1001 -0
  225. chia/_tests/pools/test_pool_config.py +42 -0
  226. chia/_tests/pools/test_pool_puzzles_lifecycle.py +397 -0
  227. chia/_tests/pools/test_pool_rpc.py +1123 -0
  228. chia/_tests/pools/test_pool_wallet.py +205 -0
  229. chia/_tests/pools/test_wallet_pool_store.py +161 -0
  230. chia/_tests/process_junit.py +348 -0
  231. chia/_tests/rpc/__init__.py +0 -0
  232. chia/_tests/rpc/test_rpc_client.py +138 -0
  233. chia/_tests/rpc/test_rpc_server.py +183 -0
  234. chia/_tests/simulation/__init__.py +0 -0
  235. chia/_tests/simulation/config.py +6 -0
  236. chia/_tests/simulation/test_simulation.py +501 -0
  237. chia/_tests/simulation/test_simulator.py +232 -0
  238. chia/_tests/simulation/test_start_simulator.py +107 -0
  239. chia/_tests/testconfig.py +13 -0
  240. chia/_tests/timelord/__init__.py +0 -0
  241. chia/_tests/timelord/config.py +3 -0
  242. chia/_tests/timelord/test_new_peak.py +437 -0
  243. chia/_tests/timelord/test_timelord.py +11 -0
  244. chia/_tests/tools/1315537.json +170 -0
  245. chia/_tests/tools/1315544.json +160 -0
  246. chia/_tests/tools/1315630.json +150 -0
  247. chia/_tests/tools/300000.json +105 -0
  248. chia/_tests/tools/442734.json +140 -0
  249. chia/_tests/tools/466212.json +130 -0
  250. chia/_tests/tools/__init__.py +0 -0
  251. chia/_tests/tools/config.py +5 -0
  252. chia/_tests/tools/test-blockchain-db.sqlite +0 -0
  253. chia/_tests/tools/test_full_sync.py +30 -0
  254. chia/_tests/tools/test_legacy_keyring.py +82 -0
  255. chia/_tests/tools/test_run_block.py +128 -0
  256. chia/_tests/tools/test_virtual_project.py +591 -0
  257. chia/_tests/util/__init__.py +0 -0
  258. chia/_tests/util/benchmark_cost.py +170 -0
  259. chia/_tests/util/benchmarks.py +153 -0
  260. chia/_tests/util/bip39_test_vectors.json +148 -0
  261. chia/_tests/util/blockchain.py +134 -0
  262. chia/_tests/util/blockchain_mock.py +132 -0
  263. chia/_tests/util/build_network_protocol_files.py +302 -0
  264. chia/_tests/util/clvm_generator.bin +0 -0
  265. chia/_tests/util/config.py +3 -0
  266. chia/_tests/util/constants.py +20 -0
  267. chia/_tests/util/db_connection.py +37 -0
  268. chia/_tests/util/full_sync.py +253 -0
  269. chia/_tests/util/gen_ssl_certs.py +114 -0
  270. chia/_tests/util/generator_tools_testing.py +45 -0
  271. chia/_tests/util/get_name_puzzle_conditions.py +52 -0
  272. chia/_tests/util/key_tool.py +36 -0
  273. chia/_tests/util/misc.py +675 -0
  274. chia/_tests/util/network_protocol_data.py +1072 -0
  275. chia/_tests/util/protocol_messages_bytes-v1.0 +0 -0
  276. chia/_tests/util/protocol_messages_json.py +2701 -0
  277. chia/_tests/util/rpc.py +26 -0
  278. chia/_tests/util/run_block.py +163 -0
  279. chia/_tests/util/setup_nodes.py +481 -0
  280. chia/_tests/util/spend_sim.py +492 -0
  281. chia/_tests/util/split_managers.py +102 -0
  282. chia/_tests/util/temp_file.py +14 -0
  283. chia/_tests/util/test_action_scope.py +144 -0
  284. chia/_tests/util/test_async_pool.py +366 -0
  285. chia/_tests/util/test_build_job_matrix.py +42 -0
  286. chia/_tests/util/test_build_network_protocol_files.py +7 -0
  287. chia/_tests/util/test_chia_version.py +50 -0
  288. chia/_tests/util/test_collection.py +11 -0
  289. chia/_tests/util/test_condition_tools.py +229 -0
  290. chia/_tests/util/test_config.py +426 -0
  291. chia/_tests/util/test_dump_keyring.py +60 -0
  292. chia/_tests/util/test_errors.py +10 -0
  293. chia/_tests/util/test_full_block_utils.py +279 -0
  294. chia/_tests/util/test_installed.py +20 -0
  295. chia/_tests/util/test_limited_semaphore.py +53 -0
  296. chia/_tests/util/test_logging_filter.py +42 -0
  297. chia/_tests/util/test_misc.py +445 -0
  298. chia/_tests/util/test_network.py +73 -0
  299. chia/_tests/util/test_network_protocol_files.py +578 -0
  300. chia/_tests/util/test_network_protocol_json.py +267 -0
  301. chia/_tests/util/test_network_protocol_test.py +256 -0
  302. chia/_tests/util/test_paginator.py +71 -0
  303. chia/_tests/util/test_pprint.py +17 -0
  304. chia/_tests/util/test_priority_mutex.py +488 -0
  305. chia/_tests/util/test_recursive_replace.py +116 -0
  306. chia/_tests/util/test_replace_str_to_bytes.py +137 -0
  307. chia/_tests/util/test_service_groups.py +15 -0
  308. chia/_tests/util/test_ssl_check.py +31 -0
  309. chia/_tests/util/test_testnet_overrides.py +19 -0
  310. chia/_tests/util/test_tests_misc.py +38 -0
  311. chia/_tests/util/test_timing.py +37 -0
  312. chia/_tests/util/test_trusted_peer.py +51 -0
  313. chia/_tests/util/time_out_assert.py +191 -0
  314. chia/_tests/wallet/__init__.py +0 -0
  315. chia/_tests/wallet/cat_wallet/__init__.py +0 -0
  316. chia/_tests/wallet/cat_wallet/config.py +4 -0
  317. chia/_tests/wallet/cat_wallet/test_cat_lifecycle.py +468 -0
  318. chia/_tests/wallet/cat_wallet/test_cat_outer_puzzle.py +69 -0
  319. chia/_tests/wallet/cat_wallet/test_cat_wallet.py +1826 -0
  320. chia/_tests/wallet/cat_wallet/test_offer_lifecycle.py +291 -0
  321. chia/_tests/wallet/cat_wallet/test_trades.py +2600 -0
  322. chia/_tests/wallet/clawback/__init__.py +0 -0
  323. chia/_tests/wallet/clawback/config.py +3 -0
  324. chia/_tests/wallet/clawback/test_clawback_decorator.py +78 -0
  325. chia/_tests/wallet/clawback/test_clawback_lifecycle.py +292 -0
  326. chia/_tests/wallet/clawback/test_clawback_metadata.py +50 -0
  327. chia/_tests/wallet/config.py +4 -0
  328. chia/_tests/wallet/conftest.py +278 -0
  329. chia/_tests/wallet/dao_wallet/__init__.py +0 -0
  330. chia/_tests/wallet/dao_wallet/config.py +3 -0
  331. chia/_tests/wallet/dao_wallet/test_dao_clvm.py +1330 -0
  332. chia/_tests/wallet/dao_wallet/test_dao_wallets.py +3488 -0
  333. chia/_tests/wallet/db_wallet/__init__.py +0 -0
  334. chia/_tests/wallet/db_wallet/config.py +3 -0
  335. chia/_tests/wallet/db_wallet/test_db_graftroot.py +141 -0
  336. chia/_tests/wallet/db_wallet/test_dl_offers.py +491 -0
  337. chia/_tests/wallet/db_wallet/test_dl_wallet.py +823 -0
  338. chia/_tests/wallet/did_wallet/__init__.py +0 -0
  339. chia/_tests/wallet/did_wallet/config.py +4 -0
  340. chia/_tests/wallet/did_wallet/test_did.py +2284 -0
  341. chia/_tests/wallet/nft_wallet/__init__.py +0 -0
  342. chia/_tests/wallet/nft_wallet/config.py +4 -0
  343. chia/_tests/wallet/nft_wallet/test_nft_1_offers.py +1493 -0
  344. chia/_tests/wallet/nft_wallet/test_nft_bulk_mint.py +1024 -0
  345. chia/_tests/wallet/nft_wallet/test_nft_lifecycle.py +375 -0
  346. chia/_tests/wallet/nft_wallet/test_nft_offers.py +1209 -0
  347. chia/_tests/wallet/nft_wallet/test_nft_puzzles.py +172 -0
  348. chia/_tests/wallet/nft_wallet/test_nft_wallet.py +2584 -0
  349. chia/_tests/wallet/nft_wallet/test_ownership_outer_puzzle.py +70 -0
  350. chia/_tests/wallet/rpc/__init__.py +0 -0
  351. chia/_tests/wallet/rpc/config.py +4 -0
  352. chia/_tests/wallet/rpc/test_dl_wallet_rpc.py +285 -0
  353. chia/_tests/wallet/rpc/test_wallet_rpc.py +3153 -0
  354. chia/_tests/wallet/simple_sync/__init__.py +0 -0
  355. chia/_tests/wallet/simple_sync/config.py +3 -0
  356. chia/_tests/wallet/simple_sync/test_simple_sync_protocol.py +718 -0
  357. chia/_tests/wallet/sync/__init__.py +0 -0
  358. chia/_tests/wallet/sync/config.py +4 -0
  359. chia/_tests/wallet/sync/test_wallet_sync.py +1692 -0
  360. chia/_tests/wallet/test_address_type.py +189 -0
  361. chia/_tests/wallet/test_bech32m.py +45 -0
  362. chia/_tests/wallet/test_clvm_streamable.py +244 -0
  363. chia/_tests/wallet/test_coin_management.py +354 -0
  364. chia/_tests/wallet/test_coin_selection.py +588 -0
  365. chia/_tests/wallet/test_conditions.py +400 -0
  366. chia/_tests/wallet/test_debug_spend_bundle.py +218 -0
  367. chia/_tests/wallet/test_new_wallet_protocol.py +1174 -0
  368. chia/_tests/wallet/test_nft_store.py +192 -0
  369. chia/_tests/wallet/test_notifications.py +196 -0
  370. chia/_tests/wallet/test_offer_parsing_performance.py +48 -0
  371. chia/_tests/wallet/test_puzzle_store.py +132 -0
  372. chia/_tests/wallet/test_sign_coin_spends.py +159 -0
  373. chia/_tests/wallet/test_signer_protocol.py +947 -0
  374. chia/_tests/wallet/test_singleton.py +122 -0
  375. chia/_tests/wallet/test_singleton_lifecycle_fast.py +772 -0
  376. chia/_tests/wallet/test_singleton_store.py +152 -0
  377. chia/_tests/wallet/test_taproot.py +19 -0
  378. chia/_tests/wallet/test_transaction_store.py +945 -0
  379. chia/_tests/wallet/test_util.py +185 -0
  380. chia/_tests/wallet/test_wallet.py +2139 -0
  381. chia/_tests/wallet/test_wallet_action_scope.py +85 -0
  382. chia/_tests/wallet/test_wallet_blockchain.py +111 -0
  383. chia/_tests/wallet/test_wallet_coin_store.py +1002 -0
  384. chia/_tests/wallet/test_wallet_interested_store.py +43 -0
  385. chia/_tests/wallet/test_wallet_key_val_store.py +40 -0
  386. chia/_tests/wallet/test_wallet_node.py +780 -0
  387. chia/_tests/wallet/test_wallet_retry.py +95 -0
  388. chia/_tests/wallet/test_wallet_state_manager.py +259 -0
  389. chia/_tests/wallet/test_wallet_test_framework.py +275 -0
  390. chia/_tests/wallet/test_wallet_trade_store.py +218 -0
  391. chia/_tests/wallet/test_wallet_user_store.py +34 -0
  392. chia/_tests/wallet/test_wallet_utils.py +156 -0
  393. chia/_tests/wallet/vc_wallet/__init__.py +0 -0
  394. chia/_tests/wallet/vc_wallet/config.py +3 -0
  395. chia/_tests/wallet/vc_wallet/test_cr_outer_puzzle.py +70 -0
  396. chia/_tests/wallet/vc_wallet/test_vc_lifecycle.py +883 -0
  397. chia/_tests/wallet/vc_wallet/test_vc_wallet.py +830 -0
  398. chia/_tests/wallet/wallet_block_tools.py +327 -0
  399. chia/_tests/weight_proof/__init__.py +0 -0
  400. chia/_tests/weight_proof/config.py +3 -0
  401. chia/_tests/weight_proof/test_weight_proof.py +528 -0
  402. chia/apis.py +19 -0
  403. chia/clvm/__init__.py +0 -0
  404. chia/cmds/__init__.py +0 -0
  405. chia/cmds/beta.py +184 -0
  406. chia/cmds/beta_funcs.py +137 -0
  407. chia/cmds/check_wallet_db.py +420 -0
  408. chia/cmds/chia.py +151 -0
  409. chia/cmds/cmd_classes.py +323 -0
  410. chia/cmds/cmd_helpers.py +242 -0
  411. chia/cmds/cmds_util.py +488 -0
  412. chia/cmds/coin_funcs.py +275 -0
  413. chia/cmds/coins.py +182 -0
  414. chia/cmds/completion.py +49 -0
  415. chia/cmds/configure.py +332 -0
  416. chia/cmds/dao.py +1064 -0
  417. chia/cmds/dao_funcs.py +598 -0
  418. chia/cmds/data.py +708 -0
  419. chia/cmds/data_funcs.py +385 -0
  420. chia/cmds/db.py +87 -0
  421. chia/cmds/db_backup_func.py +77 -0
  422. chia/cmds/db_upgrade_func.py +452 -0
  423. chia/cmds/db_validate_func.py +184 -0
  424. chia/cmds/dev.py +18 -0
  425. chia/cmds/farm.py +100 -0
  426. chia/cmds/farm_funcs.py +200 -0
  427. chia/cmds/gh.py +275 -0
  428. chia/cmds/init.py +63 -0
  429. chia/cmds/init_funcs.py +367 -0
  430. chia/cmds/installers.py +131 -0
  431. chia/cmds/keys.py +527 -0
  432. chia/cmds/keys_funcs.py +863 -0
  433. chia/cmds/netspace.py +50 -0
  434. chia/cmds/netspace_funcs.py +54 -0
  435. chia/cmds/options.py +32 -0
  436. chia/cmds/param_types.py +238 -0
  437. chia/cmds/passphrase.py +131 -0
  438. chia/cmds/passphrase_funcs.py +292 -0
  439. chia/cmds/peer.py +51 -0
  440. chia/cmds/peer_funcs.py +129 -0
  441. chia/cmds/plotnft.py +260 -0
  442. chia/cmds/plotnft_funcs.py +405 -0
  443. chia/cmds/plots.py +230 -0
  444. chia/cmds/plotters.py +18 -0
  445. chia/cmds/rpc.py +208 -0
  446. chia/cmds/show.py +72 -0
  447. chia/cmds/show_funcs.py +215 -0
  448. chia/cmds/signer.py +296 -0
  449. chia/cmds/sim.py +225 -0
  450. chia/cmds/sim_funcs.py +509 -0
  451. chia/cmds/start.py +24 -0
  452. chia/cmds/start_funcs.py +109 -0
  453. chia/cmds/stop.py +62 -0
  454. chia/cmds/units.py +9 -0
  455. chia/cmds/wallet.py +1901 -0
  456. chia/cmds/wallet_funcs.py +1874 -0
  457. chia/consensus/__init__.py +0 -0
  458. chia/consensus/block_body_validation.py +562 -0
  459. chia/consensus/block_creation.py +546 -0
  460. chia/consensus/block_header_validation.py +1059 -0
  461. chia/consensus/block_record.py +31 -0
  462. chia/consensus/block_rewards.py +53 -0
  463. chia/consensus/blockchain.py +1087 -0
  464. chia/consensus/blockchain_interface.py +56 -0
  465. chia/consensus/coinbase.py +30 -0
  466. chia/consensus/condition_costs.py +9 -0
  467. chia/consensus/constants.py +49 -0
  468. chia/consensus/cost_calculator.py +15 -0
  469. chia/consensus/default_constants.py +89 -0
  470. chia/consensus/deficit.py +55 -0
  471. chia/consensus/difficulty_adjustment.py +412 -0
  472. chia/consensus/find_fork_point.py +111 -0
  473. chia/consensus/full_block_to_block_record.py +167 -0
  474. chia/consensus/get_block_challenge.py +106 -0
  475. chia/consensus/get_block_generator.py +27 -0
  476. chia/consensus/make_sub_epoch_summary.py +210 -0
  477. chia/consensus/multiprocess_validation.py +268 -0
  478. chia/consensus/pos_quality.py +19 -0
  479. chia/consensus/pot_iterations.py +67 -0
  480. chia/consensus/puzzles/__init__.py +0 -0
  481. chia/consensus/puzzles/chialisp_deserialisation.clsp +69 -0
  482. chia/consensus/puzzles/chialisp_deserialisation.clsp.hex +1 -0
  483. chia/consensus/puzzles/rom_bootstrap_generator.clsp +37 -0
  484. chia/consensus/puzzles/rom_bootstrap_generator.clsp.hex +1 -0
  485. chia/consensus/vdf_info_computation.py +156 -0
  486. chia/daemon/__init__.py +0 -0
  487. chia/daemon/client.py +252 -0
  488. chia/daemon/keychain_proxy.py +502 -0
  489. chia/daemon/keychain_server.py +365 -0
  490. chia/daemon/server.py +1606 -0
  491. chia/daemon/windows_signal.py +56 -0
  492. chia/data_layer/__init__.py +0 -0
  493. chia/data_layer/data_layer.py +1291 -0
  494. chia/data_layer/data_layer_api.py +33 -0
  495. chia/data_layer/data_layer_errors.py +50 -0
  496. chia/data_layer/data_layer_server.py +170 -0
  497. chia/data_layer/data_layer_util.py +985 -0
  498. chia/data_layer/data_layer_wallet.py +1311 -0
  499. chia/data_layer/data_store.py +2267 -0
  500. chia/data_layer/dl_wallet_store.py +407 -0
  501. chia/data_layer/download_data.py +389 -0
  502. chia/data_layer/puzzles/__init__.py +0 -0
  503. chia/data_layer/puzzles/graftroot_dl_offers.clsp +100 -0
  504. chia/data_layer/puzzles/graftroot_dl_offers.clsp.hex +1 -0
  505. chia/data_layer/s3_plugin_config.yml +33 -0
  506. chia/data_layer/s3_plugin_service.py +468 -0
  507. chia/data_layer/util/__init__.py +0 -0
  508. chia/data_layer/util/benchmark.py +107 -0
  509. chia/data_layer/util/plugin.py +40 -0
  510. chia/farmer/__init__.py +0 -0
  511. chia/farmer/farmer.py +923 -0
  512. chia/farmer/farmer_api.py +820 -0
  513. chia/full_node/__init__.py +0 -0
  514. chia/full_node/bitcoin_fee_estimator.py +85 -0
  515. chia/full_node/block_height_map.py +271 -0
  516. chia/full_node/block_store.py +576 -0
  517. chia/full_node/bundle_tools.py +19 -0
  518. chia/full_node/coin_store.py +647 -0
  519. chia/full_node/fee_estimate.py +54 -0
  520. chia/full_node/fee_estimate_store.py +24 -0
  521. chia/full_node/fee_estimation.py +92 -0
  522. chia/full_node/fee_estimator.py +90 -0
  523. chia/full_node/fee_estimator_constants.py +38 -0
  524. chia/full_node/fee_estimator_interface.py +42 -0
  525. chia/full_node/fee_history.py +25 -0
  526. chia/full_node/fee_tracker.py +564 -0
  527. chia/full_node/full_node.py +3327 -0
  528. chia/full_node/full_node_api.py +2025 -0
  529. chia/full_node/full_node_store.py +1033 -0
  530. chia/full_node/hint_management.py +56 -0
  531. chia/full_node/hint_store.py +93 -0
  532. chia/full_node/mempool.py +589 -0
  533. chia/full_node/mempool_check_conditions.py +146 -0
  534. chia/full_node/mempool_manager.py +853 -0
  535. chia/full_node/pending_tx_cache.py +112 -0
  536. chia/full_node/puzzles/__init__.py +0 -0
  537. chia/full_node/puzzles/block_program_zero.clsp +14 -0
  538. chia/full_node/puzzles/block_program_zero.clsp.hex +1 -0
  539. chia/full_node/puzzles/decompress_coin_spend_entry.clsp +5 -0
  540. chia/full_node/puzzles/decompress_coin_spend_entry.clsp.hex +1 -0
  541. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp +7 -0
  542. chia/full_node/puzzles/decompress_coin_spend_entry_with_prefix.clsp.hex +1 -0
  543. chia/full_node/puzzles/decompress_puzzle.clsp +6 -0
  544. chia/full_node/puzzles/decompress_puzzle.clsp.hex +1 -0
  545. chia/full_node/signage_point.py +16 -0
  546. chia/full_node/subscriptions.py +247 -0
  547. chia/full_node/sync_store.py +146 -0
  548. chia/full_node/tx_processing_queue.py +78 -0
  549. chia/full_node/util/__init__.py +0 -0
  550. chia/full_node/weight_proof.py +1720 -0
  551. chia/harvester/__init__.py +0 -0
  552. chia/harvester/harvester.py +272 -0
  553. chia/harvester/harvester_api.py +380 -0
  554. chia/introducer/__init__.py +0 -0
  555. chia/introducer/introducer.py +122 -0
  556. chia/introducer/introducer_api.py +70 -0
  557. chia/legacy/__init__.py +0 -0
  558. chia/legacy/keyring.py +155 -0
  559. chia/plot_sync/__init__.py +0 -0
  560. chia/plot_sync/delta.py +61 -0
  561. chia/plot_sync/exceptions.py +56 -0
  562. chia/plot_sync/receiver.py +386 -0
  563. chia/plot_sync/sender.py +340 -0
  564. chia/plot_sync/util.py +43 -0
  565. chia/plotters/__init__.py +0 -0
  566. chia/plotters/bladebit.py +388 -0
  567. chia/plotters/chiapos.py +63 -0
  568. chia/plotters/madmax.py +224 -0
  569. chia/plotters/plotters.py +577 -0
  570. chia/plotters/plotters_util.py +133 -0
  571. chia/plotting/__init__.py +0 -0
  572. chia/plotting/cache.py +213 -0
  573. chia/plotting/check_plots.py +283 -0
  574. chia/plotting/create_plots.py +278 -0
  575. chia/plotting/manager.py +436 -0
  576. chia/plotting/util.py +336 -0
  577. chia/pools/__init__.py +0 -0
  578. chia/pools/pool_config.py +110 -0
  579. chia/pools/pool_puzzles.py +459 -0
  580. chia/pools/pool_wallet.py +933 -0
  581. chia/pools/pool_wallet_info.py +118 -0
  582. chia/pools/puzzles/__init__.py +0 -0
  583. chia/pools/puzzles/pool_member_innerpuz.clsp +70 -0
  584. chia/pools/puzzles/pool_member_innerpuz.clsp.hex +1 -0
  585. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp +69 -0
  586. chia/pools/puzzles/pool_waitingroom_innerpuz.clsp.hex +1 -0
  587. chia/protocols/__init__.py +0 -0
  588. chia/protocols/farmer_protocol.py +102 -0
  589. chia/protocols/full_node_protocol.py +219 -0
  590. chia/protocols/harvester_protocol.py +216 -0
  591. chia/protocols/introducer_protocol.py +25 -0
  592. chia/protocols/pool_protocol.py +177 -0
  593. chia/protocols/protocol_message_types.py +139 -0
  594. chia/protocols/protocol_state_machine.py +87 -0
  595. chia/protocols/protocol_timing.py +8 -0
  596. chia/protocols/shared_protocol.py +86 -0
  597. chia/protocols/timelord_protocol.py +93 -0
  598. chia/protocols/wallet_protocol.py +401 -0
  599. chia/py.typed +0 -0
  600. chia/rpc/__init__.py +0 -0
  601. chia/rpc/crawler_rpc_api.py +80 -0
  602. chia/rpc/data_layer_rpc_api.py +644 -0
  603. chia/rpc/data_layer_rpc_client.py +188 -0
  604. chia/rpc/data_layer_rpc_util.py +58 -0
  605. chia/rpc/farmer_rpc_api.py +365 -0
  606. chia/rpc/farmer_rpc_client.py +86 -0
  607. chia/rpc/full_node_rpc_api.py +959 -0
  608. chia/rpc/full_node_rpc_client.py +292 -0
  609. chia/rpc/harvester_rpc_api.py +141 -0
  610. chia/rpc/harvester_rpc_client.py +54 -0
  611. chia/rpc/rpc_client.py +164 -0
  612. chia/rpc/rpc_server.py +521 -0
  613. chia/rpc/timelord_rpc_api.py +32 -0
  614. chia/rpc/util.py +93 -0
  615. chia/rpc/wallet_request_types.py +904 -0
  616. chia/rpc/wallet_rpc_api.py +4943 -0
  617. chia/rpc/wallet_rpc_client.py +1814 -0
  618. chia/seeder/__init__.py +0 -0
  619. chia/seeder/crawl_store.py +425 -0
  620. chia/seeder/crawler.py +410 -0
  621. chia/seeder/crawler_api.py +135 -0
  622. chia/seeder/dns_server.py +593 -0
  623. chia/seeder/peer_record.py +146 -0
  624. chia/seeder/start_crawler.py +92 -0
  625. chia/server/__init__.py +0 -0
  626. chia/server/address_manager.py +658 -0
  627. chia/server/address_manager_store.py +237 -0
  628. chia/server/api_protocol.py +116 -0
  629. chia/server/capabilities.py +24 -0
  630. chia/server/chia_policy.py +346 -0
  631. chia/server/introducer_peers.py +76 -0
  632. chia/server/node_discovery.py +714 -0
  633. chia/server/outbound_message.py +33 -0
  634. chia/server/rate_limit_numbers.py +214 -0
  635. chia/server/rate_limits.py +153 -0
  636. chia/server/server.py +741 -0
  637. chia/server/signal_handlers.py +120 -0
  638. chia/server/ssl_context.py +32 -0
  639. chia/server/start_data_layer.py +151 -0
  640. chia/server/start_farmer.py +98 -0
  641. chia/server/start_full_node.py +112 -0
  642. chia/server/start_harvester.py +93 -0
  643. chia/server/start_introducer.py +81 -0
  644. chia/server/start_service.py +316 -0
  645. chia/server/start_timelord.py +89 -0
  646. chia/server/start_wallet.py +113 -0
  647. chia/server/upnp.py +118 -0
  648. chia/server/ws_connection.py +766 -0
  649. chia/simulator/__init__.py +0 -0
  650. chia/simulator/add_blocks_in_batches.py +54 -0
  651. chia/simulator/block_tools.py +2054 -0
  652. chia/simulator/full_node_simulator.py +794 -0
  653. chia/simulator/keyring.py +128 -0
  654. chia/simulator/setup_services.py +506 -0
  655. chia/simulator/simulator_constants.py +13 -0
  656. chia/simulator/simulator_full_node_rpc_api.py +99 -0
  657. chia/simulator/simulator_full_node_rpc_client.py +60 -0
  658. chia/simulator/simulator_protocol.py +29 -0
  659. chia/simulator/simulator_test_tools.py +164 -0
  660. chia/simulator/socket.py +24 -0
  661. chia/simulator/ssl_certs.py +114 -0
  662. chia/simulator/ssl_certs_1.py +697 -0
  663. chia/simulator/ssl_certs_10.py +697 -0
  664. chia/simulator/ssl_certs_2.py +697 -0
  665. chia/simulator/ssl_certs_3.py +697 -0
  666. chia/simulator/ssl_certs_4.py +697 -0
  667. chia/simulator/ssl_certs_5.py +697 -0
  668. chia/simulator/ssl_certs_6.py +697 -0
  669. chia/simulator/ssl_certs_7.py +697 -0
  670. chia/simulator/ssl_certs_8.py +697 -0
  671. chia/simulator/ssl_certs_9.py +697 -0
  672. chia/simulator/start_simulator.py +143 -0
  673. chia/simulator/wallet_tools.py +246 -0
  674. chia/ssl/__init__.py +0 -0
  675. chia/ssl/chia_ca.crt +19 -0
  676. chia/ssl/chia_ca.key +28 -0
  677. chia/ssl/create_ssl.py +249 -0
  678. chia/ssl/dst_root_ca.pem +20 -0
  679. chia/timelord/__init__.py +0 -0
  680. chia/timelord/iters_from_block.py +50 -0
  681. chia/timelord/timelord.py +1226 -0
  682. chia/timelord/timelord_api.py +138 -0
  683. chia/timelord/timelord_launcher.py +190 -0
  684. chia/timelord/timelord_state.py +244 -0
  685. chia/timelord/types.py +22 -0
  686. chia/types/__init__.py +0 -0
  687. chia/types/aliases.py +35 -0
  688. chia/types/block_protocol.py +20 -0
  689. chia/types/blockchain_format/__init__.py +0 -0
  690. chia/types/blockchain_format/classgroup.py +5 -0
  691. chia/types/blockchain_format/coin.py +28 -0
  692. chia/types/blockchain_format/foliage.py +8 -0
  693. chia/types/blockchain_format/pool_target.py +5 -0
  694. chia/types/blockchain_format/program.py +269 -0
  695. chia/types/blockchain_format/proof_of_space.py +135 -0
  696. chia/types/blockchain_format/reward_chain_block.py +6 -0
  697. chia/types/blockchain_format/serialized_program.py +5 -0
  698. chia/types/blockchain_format/sized_bytes.py +11 -0
  699. chia/types/blockchain_format/slots.py +9 -0
  700. chia/types/blockchain_format/sub_epoch_summary.py +5 -0
  701. chia/types/blockchain_format/tree_hash.py +72 -0
  702. chia/types/blockchain_format/vdf.py +86 -0
  703. chia/types/clvm_cost.py +13 -0
  704. chia/types/coin_record.py +43 -0
  705. chia/types/coin_spend.py +115 -0
  706. chia/types/condition_opcodes.py +73 -0
  707. chia/types/condition_with_args.py +16 -0
  708. chia/types/eligible_coin_spends.py +365 -0
  709. chia/types/end_of_slot_bundle.py +5 -0
  710. chia/types/fee_rate.py +38 -0
  711. chia/types/full_block.py +5 -0
  712. chia/types/generator_types.py +13 -0
  713. chia/types/header_block.py +5 -0
  714. chia/types/internal_mempool_item.py +18 -0
  715. chia/types/mempool_inclusion_status.py +9 -0
  716. chia/types/mempool_item.py +85 -0
  717. chia/types/mempool_submission_status.py +30 -0
  718. chia/types/mojos.py +7 -0
  719. chia/types/peer_info.py +64 -0
  720. chia/types/signing_mode.py +29 -0
  721. chia/types/spend_bundle.py +30 -0
  722. chia/types/spend_bundle_conditions.py +7 -0
  723. chia/types/transaction_queue_entry.py +55 -0
  724. chia/types/unfinished_block.py +5 -0
  725. chia/types/unfinished_header_block.py +37 -0
  726. chia/types/validation_state.py +14 -0
  727. chia/types/weight_proof.py +49 -0
  728. chia/util/__init__.py +0 -0
  729. chia/util/action_scope.py +168 -0
  730. chia/util/async_pool.py +226 -0
  731. chia/util/augmented_chain.py +134 -0
  732. chia/util/batches.py +42 -0
  733. chia/util/bech32m.py +126 -0
  734. chia/util/beta_metrics.py +119 -0
  735. chia/util/block_cache.py +56 -0
  736. chia/util/byte_types.py +12 -0
  737. chia/util/check_fork_next_block.py +33 -0
  738. chia/util/chia_logging.py +144 -0
  739. chia/util/chia_version.py +33 -0
  740. chia/util/collection.py +17 -0
  741. chia/util/condition_tools.py +201 -0
  742. chia/util/config.py +367 -0
  743. chia/util/cpu.py +22 -0
  744. chia/util/db_synchronous.py +23 -0
  745. chia/util/db_version.py +32 -0
  746. chia/util/db_wrapper.py +430 -0
  747. chia/util/default_root.py +27 -0
  748. chia/util/dump_keyring.py +93 -0
  749. chia/util/english.txt +2048 -0
  750. chia/util/errors.py +353 -0
  751. chia/util/file_keyring.py +469 -0
  752. chia/util/files.py +97 -0
  753. chia/util/full_block_utils.py +345 -0
  754. chia/util/generator_tools.py +72 -0
  755. chia/util/hash.py +31 -0
  756. chia/util/initial-config.yaml +694 -0
  757. chia/util/inline_executor.py +26 -0
  758. chia/util/ints.py +19 -0
  759. chia/util/ip_address.py +39 -0
  760. chia/util/json_util.py +37 -0
  761. chia/util/keychain.py +676 -0
  762. chia/util/keyring_wrapper.py +327 -0
  763. chia/util/limited_semaphore.py +41 -0
  764. chia/util/lock.py +49 -0
  765. chia/util/log_exceptions.py +32 -0
  766. chia/util/logging.py +36 -0
  767. chia/util/lru_cache.py +31 -0
  768. chia/util/math.py +20 -0
  769. chia/util/network.py +182 -0
  770. chia/util/paginator.py +48 -0
  771. chia/util/path.py +31 -0
  772. chia/util/permissions.py +20 -0
  773. chia/util/prev_transaction_block.py +21 -0
  774. chia/util/priority_mutex.py +95 -0
  775. chia/util/profiler.py +197 -0
  776. chia/util/recursive_replace.py +24 -0
  777. chia/util/safe_cancel_task.py +16 -0
  778. chia/util/service_groups.py +47 -0
  779. chia/util/setproctitle.py +22 -0
  780. chia/util/significant_bits.py +32 -0
  781. chia/util/ssl_check.py +213 -0
  782. chia/util/streamable.py +642 -0
  783. chia/util/task_referencer.py +59 -0
  784. chia/util/task_timing.py +382 -0
  785. chia/util/timing.py +67 -0
  786. chia/util/vdf_prover.py +30 -0
  787. chia/util/virtual_project_analysis.py +540 -0
  788. chia/util/ws_message.py +66 -0
  789. chia/wallet/__init__.py +0 -0
  790. chia/wallet/cat_wallet/__init__.py +0 -0
  791. chia/wallet/cat_wallet/cat_constants.py +75 -0
  792. chia/wallet/cat_wallet/cat_info.py +47 -0
  793. chia/wallet/cat_wallet/cat_outer_puzzle.py +120 -0
  794. chia/wallet/cat_wallet/cat_utils.py +164 -0
  795. chia/wallet/cat_wallet/cat_wallet.py +855 -0
  796. chia/wallet/cat_wallet/dao_cat_info.py +28 -0
  797. chia/wallet/cat_wallet/dao_cat_wallet.py +669 -0
  798. chia/wallet/cat_wallet/lineage_store.py +74 -0
  799. chia/wallet/cat_wallet/puzzles/__init__.py +0 -0
  800. chia/wallet/cat_wallet/puzzles/cat_truths.clib +31 -0
  801. chia/wallet/cat_wallet/puzzles/cat_v2.clsp +397 -0
  802. chia/wallet/cat_wallet/puzzles/cat_v2.clsp.hex +1 -0
  803. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp +25 -0
  804. chia/wallet/cat_wallet/puzzles/delegated_tail.clsp.hex +1 -0
  805. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp +15 -0
  806. chia/wallet/cat_wallet/puzzles/everything_with_signature.clsp.hex +1 -0
  807. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp +26 -0
  808. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id.clsp.hex +1 -0
  809. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp +42 -0
  810. chia/wallet/cat_wallet/puzzles/genesis_by_coin_id_or_singleton.clsp.hex +1 -0
  811. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp +24 -0
  812. chia/wallet/cat_wallet/puzzles/genesis_by_puzzle_hash.clsp.hex +1 -0
  813. chia/wallet/coin_selection.py +188 -0
  814. chia/wallet/conditions.py +1512 -0
  815. chia/wallet/dao_wallet/__init__.py +0 -0
  816. chia/wallet/dao_wallet/dao_info.py +61 -0
  817. chia/wallet/dao_wallet/dao_utils.py +811 -0
  818. chia/wallet/dao_wallet/dao_wallet.py +2119 -0
  819. chia/wallet/db_wallet/__init__.py +0 -0
  820. chia/wallet/db_wallet/db_wallet_puzzles.py +111 -0
  821. chia/wallet/derivation_record.py +30 -0
  822. chia/wallet/derive_keys.py +146 -0
  823. chia/wallet/did_wallet/__init__.py +0 -0
  824. chia/wallet/did_wallet/did_info.py +39 -0
  825. chia/wallet/did_wallet/did_wallet.py +1494 -0
  826. chia/wallet/did_wallet/did_wallet_puzzles.py +221 -0
  827. chia/wallet/did_wallet/puzzles/__init__.py +0 -0
  828. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp +135 -0
  829. chia/wallet/did_wallet/puzzles/did_innerpuz.clsp.hex +1 -0
  830. chia/wallet/driver_protocol.py +26 -0
  831. chia/wallet/key_val_store.py +55 -0
  832. chia/wallet/lineage_proof.py +58 -0
  833. chia/wallet/nft_wallet/__init__.py +0 -0
  834. chia/wallet/nft_wallet/metadata_outer_puzzle.py +92 -0
  835. chia/wallet/nft_wallet/nft_info.py +120 -0
  836. chia/wallet/nft_wallet/nft_puzzles.py +305 -0
  837. chia/wallet/nft_wallet/nft_wallet.py +1687 -0
  838. chia/wallet/nft_wallet/ownership_outer_puzzle.py +101 -0
  839. chia/wallet/nft_wallet/puzzles/__init__.py +0 -0
  840. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp +6 -0
  841. chia/wallet/nft_wallet/puzzles/create_nft_launcher_from_did.clsp.hex +1 -0
  842. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp +6 -0
  843. chia/wallet/nft_wallet/puzzles/nft_intermediate_launcher.clsp.hex +1 -0
  844. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp +30 -0
  845. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_default.clsp.hex +1 -0
  846. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp +28 -0
  847. chia/wallet/nft_wallet/puzzles/nft_metadata_updater_updateable.clsp.hex +1 -0
  848. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp +100 -0
  849. chia/wallet/nft_wallet/puzzles/nft_ownership_layer.clsp.hex +1 -0
  850. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp +78 -0
  851. chia/wallet/nft_wallet/puzzles/nft_ownership_transfer_program_one_way_claim_with_royalties.clsp.hex +1 -0
  852. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp +74 -0
  853. chia/wallet/nft_wallet/puzzles/nft_state_layer.clsp.hex +1 -0
  854. chia/wallet/nft_wallet/singleton_outer_puzzle.py +101 -0
  855. chia/wallet/nft_wallet/transfer_program_puzzle.py +82 -0
  856. chia/wallet/nft_wallet/uncurry_nft.py +217 -0
  857. chia/wallet/notification_manager.py +117 -0
  858. chia/wallet/notification_store.py +178 -0
  859. chia/wallet/outer_puzzles.py +84 -0
  860. chia/wallet/payment.py +33 -0
  861. chia/wallet/puzzle_drivers.py +118 -0
  862. chia/wallet/puzzles/__init__.py +0 -0
  863. chia/wallet/puzzles/augmented_condition.clsp +13 -0
  864. chia/wallet/puzzles/augmented_condition.clsp.hex +1 -0
  865. chia/wallet/puzzles/clawback/__init__.py +0 -0
  866. chia/wallet/puzzles/clawback/drivers.py +188 -0
  867. chia/wallet/puzzles/clawback/metadata.py +38 -0
  868. chia/wallet/puzzles/clawback/puzzle_decorator.py +67 -0
  869. chia/wallet/puzzles/condition_codes.clib +77 -0
  870. chia/wallet/puzzles/curry-and-treehash.clib +102 -0
  871. chia/wallet/puzzles/curry.clib +135 -0
  872. chia/wallet/puzzles/curry_by_index.clib +16 -0
  873. chia/wallet/puzzles/dao_cat_eve.clsp +17 -0
  874. chia/wallet/puzzles/dao_cat_eve.clsp.hex +1 -0
  875. chia/wallet/puzzles/dao_cat_launcher.clsp +36 -0
  876. chia/wallet/puzzles/dao_cat_launcher.clsp.hex +1 -0
  877. chia/wallet/puzzles/dao_finished_state.clsp +35 -0
  878. chia/wallet/puzzles/dao_finished_state.clsp.hex +1 -0
  879. chia/wallet/puzzles/dao_finished_state.clsp.hex.sha256tree +1 -0
  880. chia/wallet/puzzles/dao_lockup.clsp +288 -0
  881. chia/wallet/puzzles/dao_lockup.clsp.hex +1 -0
  882. chia/wallet/puzzles/dao_lockup.clsp.hex.sha256tree +1 -0
  883. chia/wallet/puzzles/dao_proposal.clsp +377 -0
  884. chia/wallet/puzzles/dao_proposal.clsp.hex +1 -0
  885. chia/wallet/puzzles/dao_proposal.clsp.hex.sha256tree +1 -0
  886. chia/wallet/puzzles/dao_proposal_timer.clsp +78 -0
  887. chia/wallet/puzzles/dao_proposal_timer.clsp.hex +1 -0
  888. chia/wallet/puzzles/dao_proposal_timer.clsp.hex.sha256tree +1 -0
  889. chia/wallet/puzzles/dao_proposal_validator.clsp +87 -0
  890. chia/wallet/puzzles/dao_proposal_validator.clsp.hex +1 -0
  891. chia/wallet/puzzles/dao_proposal_validator.clsp.hex.sha256tree +1 -0
  892. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp +240 -0
  893. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex +1 -0
  894. chia/wallet/puzzles/dao_spend_p2_singleton_v2.clsp.hex.sha256tree +1 -0
  895. chia/wallet/puzzles/dao_treasury.clsp +115 -0
  896. chia/wallet/puzzles/dao_treasury.clsp.hex +1 -0
  897. chia/wallet/puzzles/dao_update_proposal.clsp +44 -0
  898. chia/wallet/puzzles/dao_update_proposal.clsp.hex +1 -0
  899. chia/wallet/puzzles/deployed_puzzle_hashes.json +67 -0
  900. chia/wallet/puzzles/json.clib +25 -0
  901. chia/wallet/puzzles/load_clvm.py +161 -0
  902. chia/wallet/puzzles/merkle_utils.clib +18 -0
  903. chia/wallet/puzzles/notification.clsp +7 -0
  904. chia/wallet/puzzles/notification.clsp.hex +1 -0
  905. chia/wallet/puzzles/p2_1_of_n.clsp +22 -0
  906. chia/wallet/puzzles/p2_1_of_n.clsp.hex +1 -0
  907. chia/wallet/puzzles/p2_conditions.clsp +3 -0
  908. chia/wallet/puzzles/p2_conditions.clsp.hex +1 -0
  909. chia/wallet/puzzles/p2_conditions.py +26 -0
  910. chia/wallet/puzzles/p2_delegated_conditions.clsp +18 -0
  911. chia/wallet/puzzles/p2_delegated_conditions.clsp.hex +1 -0
  912. chia/wallet/puzzles/p2_delegated_conditions.py +21 -0
  913. chia/wallet/puzzles/p2_delegated_puzzle.clsp +19 -0
  914. chia/wallet/puzzles/p2_delegated_puzzle.clsp.hex +1 -0
  915. chia/wallet/puzzles/p2_delegated_puzzle.py +34 -0
  916. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp +91 -0
  917. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.clsp.hex +1 -0
  918. chia/wallet/puzzles/p2_delegated_puzzle_or_hidden_puzzle.py +160 -0
  919. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp +108 -0
  920. chia/wallet/puzzles/p2_m_of_n_delegate_direct.clsp.hex +1 -0
  921. chia/wallet/puzzles/p2_m_of_n_delegate_direct.py +21 -0
  922. chia/wallet/puzzles/p2_parent.clsp +19 -0
  923. chia/wallet/puzzles/p2_parent.clsp.hex +1 -0
  924. chia/wallet/puzzles/p2_puzzle_hash.clsp +18 -0
  925. chia/wallet/puzzles/p2_puzzle_hash.clsp.hex +1 -0
  926. chia/wallet/puzzles/p2_puzzle_hash.py +27 -0
  927. chia/wallet/puzzles/p2_singleton.clsp +30 -0
  928. chia/wallet/puzzles/p2_singleton.clsp.hex +1 -0
  929. chia/wallet/puzzles/p2_singleton_aggregator.clsp +81 -0
  930. chia/wallet/puzzles/p2_singleton_aggregator.clsp.hex +1 -0
  931. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp +50 -0
  932. chia/wallet/puzzles/p2_singleton_or_delayed_puzhash.clsp.hex +1 -0
  933. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp +47 -0
  934. chia/wallet/puzzles/p2_singleton_via_delegated_puzzle.clsp.hex +1 -0
  935. chia/wallet/puzzles/puzzle_utils.py +34 -0
  936. chia/wallet/puzzles/settlement_payments.clsp +49 -0
  937. chia/wallet/puzzles/settlement_payments.clsp.hex +1 -0
  938. chia/wallet/puzzles/sha256tree.clib +11 -0
  939. chia/wallet/puzzles/singleton_launcher.clsp +16 -0
  940. chia/wallet/puzzles/singleton_launcher.clsp.hex +1 -0
  941. chia/wallet/puzzles/singleton_top_layer.clsp +177 -0
  942. chia/wallet/puzzles/singleton_top_layer.clsp.hex +1 -0
  943. chia/wallet/puzzles/singleton_top_layer.py +296 -0
  944. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp +107 -0
  945. chia/wallet/puzzles/singleton_top_layer_v1_1.clsp.hex +1 -0
  946. chia/wallet/puzzles/singleton_top_layer_v1_1.py +345 -0
  947. chia/wallet/puzzles/singleton_truths.clib +21 -0
  948. chia/wallet/puzzles/tails.py +348 -0
  949. chia/wallet/puzzles/utility_macros.clib +48 -0
  950. chia/wallet/signer_protocol.py +125 -0
  951. chia/wallet/singleton.py +106 -0
  952. chia/wallet/singleton_record.py +30 -0
  953. chia/wallet/trade_manager.py +1102 -0
  954. chia/wallet/trade_record.py +67 -0
  955. chia/wallet/trading/__init__.py +0 -0
  956. chia/wallet/trading/offer.py +702 -0
  957. chia/wallet/trading/trade_status.py +13 -0
  958. chia/wallet/trading/trade_store.py +526 -0
  959. chia/wallet/transaction_record.py +158 -0
  960. chia/wallet/transaction_sorting.py +14 -0
  961. chia/wallet/uncurried_puzzle.py +17 -0
  962. chia/wallet/util/__init__.py +0 -0
  963. chia/wallet/util/address_type.py +55 -0
  964. chia/wallet/util/blind_signer_tl.py +164 -0
  965. chia/wallet/util/clvm_streamable.py +203 -0
  966. chia/wallet/util/compute_hints.py +66 -0
  967. chia/wallet/util/compute_memos.py +43 -0
  968. chia/wallet/util/curry_and_treehash.py +91 -0
  969. chia/wallet/util/debug_spend_bundle.py +232 -0
  970. chia/wallet/util/merkle_tree.py +100 -0
  971. chia/wallet/util/merkle_utils.py +102 -0
  972. chia/wallet/util/new_peak_queue.py +82 -0
  973. chia/wallet/util/notifications.py +12 -0
  974. chia/wallet/util/peer_request_cache.py +174 -0
  975. chia/wallet/util/pprint.py +39 -0
  976. chia/wallet/util/puzzle_compression.py +95 -0
  977. chia/wallet/util/puzzle_decorator.py +100 -0
  978. chia/wallet/util/puzzle_decorator_type.py +7 -0
  979. chia/wallet/util/query_filter.py +59 -0
  980. chia/wallet/util/transaction_type.py +23 -0
  981. chia/wallet/util/tx_config.py +158 -0
  982. chia/wallet/util/wallet_sync_utils.py +351 -0
  983. chia/wallet/util/wallet_types.py +72 -0
  984. chia/wallet/vc_wallet/__init__.py +0 -0
  985. chia/wallet/vc_wallet/cr_cat_drivers.py +664 -0
  986. chia/wallet/vc_wallet/cr_cat_wallet.py +877 -0
  987. chia/wallet/vc_wallet/cr_outer_puzzle.py +102 -0
  988. chia/wallet/vc_wallet/cr_puzzles/__init__.py +0 -0
  989. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp +3 -0
  990. chia/wallet/vc_wallet/cr_puzzles/conditions_w_fee_announce.clsp.hex +1 -0
  991. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp +304 -0
  992. chia/wallet/vc_wallet/cr_puzzles/credential_restriction.clsp.hex +1 -0
  993. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp +45 -0
  994. chia/wallet/vc_wallet/cr_puzzles/flag_proofs_checker.clsp.hex +1 -0
  995. chia/wallet/vc_wallet/vc_drivers.py +838 -0
  996. chia/wallet/vc_wallet/vc_puzzles/__init__.py +0 -0
  997. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp +30 -0
  998. chia/wallet/vc_wallet/vc_puzzles/covenant_layer.clsp.hex +1 -0
  999. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp +75 -0
  1000. chia/wallet/vc_wallet/vc_puzzles/eml_covenant_morpher.clsp.hex +1 -0
  1001. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp +32 -0
  1002. chia/wallet/vc_wallet/vc_puzzles/eml_transfer_program_covenant_adapter.clsp.hex +1 -0
  1003. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp +80 -0
  1004. chia/wallet/vc_wallet/vc_puzzles/eml_update_metadata_with_DID.clsp.hex +1 -0
  1005. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp +163 -0
  1006. chia/wallet/vc_wallet/vc_puzzles/exigent_metadata_layer.clsp.hex +1 -0
  1007. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp +16 -0
  1008. chia/wallet/vc_wallet/vc_puzzles/p2_announced_delegated_puzzle.clsp.hex +1 -0
  1009. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp +74 -0
  1010. chia/wallet/vc_wallet/vc_puzzles/standard_vc_backdoor_puzzle.clsp.hex +1 -0
  1011. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp +23 -0
  1012. chia/wallet/vc_wallet/vc_puzzles/std_parent_morpher.clsp.hex +1 -0
  1013. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp +64 -0
  1014. chia/wallet/vc_wallet/vc_puzzles/viral_backdoor.clsp.hex +1 -0
  1015. chia/wallet/vc_wallet/vc_store.py +263 -0
  1016. chia/wallet/vc_wallet/vc_wallet.py +638 -0
  1017. chia/wallet/wallet.py +698 -0
  1018. chia/wallet/wallet_action_scope.py +96 -0
  1019. chia/wallet/wallet_blockchain.py +244 -0
  1020. chia/wallet/wallet_coin_record.py +72 -0
  1021. chia/wallet/wallet_coin_store.py +351 -0
  1022. chia/wallet/wallet_info.py +35 -0
  1023. chia/wallet/wallet_interested_store.py +188 -0
  1024. chia/wallet/wallet_nft_store.py +279 -0
  1025. chia/wallet/wallet_node.py +1765 -0
  1026. chia/wallet/wallet_node_api.py +207 -0
  1027. chia/wallet/wallet_pool_store.py +119 -0
  1028. chia/wallet/wallet_protocol.py +90 -0
  1029. chia/wallet/wallet_puzzle_store.py +396 -0
  1030. chia/wallet/wallet_retry_store.py +70 -0
  1031. chia/wallet/wallet_singleton_store.py +259 -0
  1032. chia/wallet/wallet_spend_bundle.py +25 -0
  1033. chia/wallet/wallet_state_manager.py +2819 -0
  1034. chia/wallet/wallet_transaction_store.py +496 -0
  1035. chia/wallet/wallet_user_store.py +110 -0
  1036. chia/wallet/wallet_weight_proof_handler.py +126 -0
  1037. chia_blockchain-2.5.1rc1.dist-info/LICENSE +201 -0
  1038. chia_blockchain-2.5.1rc1.dist-info/METADATA +156 -0
  1039. chia_blockchain-2.5.1rc1.dist-info/RECORD +1042 -0
  1040. chia_blockchain-2.5.1rc1.dist-info/WHEEL +4 -0
  1041. chia_blockchain-2.5.1rc1.dist-info/entry_points.txt +17 -0
  1042. mozilla-ca/cacert.pem +3611 -0
@@ -0,0 +1,1687 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+ import json
5
+ import logging
6
+ import math
7
+ import time
8
+ from typing import TYPE_CHECKING, Any, ClassVar, Optional, TypeVar, cast
9
+
10
+ from chia_rs import AugSchemeMPL, G1Element, G2Element
11
+ from clvm.casts import int_from_bytes, int_to_bytes
12
+ from typing_extensions import Unpack
13
+
14
+ import chia.server.api_protocol
15
+ import chia.wallet.singleton
16
+ from chia.protocols.wallet_protocol import CoinState
17
+ from chia.server.ws_connection import WSChiaConnection
18
+ from chia.types.blockchain_format.coin import Coin
19
+ from chia.types.blockchain_format.program import Program
20
+ from chia.types.blockchain_format.sized_bytes import bytes32
21
+ from chia.types.coin_spend import CoinSpend, compute_additions, make_spend
22
+ from chia.types.signing_mode import CHIP_0002_SIGN_MESSAGE_PREFIX, SigningMode
23
+ from chia.util.hash import std_hash
24
+ from chia.util.ints import uint16, uint32, uint64, uint128
25
+ from chia.wallet.conditions import (
26
+ AssertCoinAnnouncement,
27
+ AssertPuzzleAnnouncement,
28
+ Condition,
29
+ CreateCoinAnnouncement,
30
+ CreatePuzzleAnnouncement,
31
+ UnknownCondition,
32
+ parse_timelock_info,
33
+ )
34
+ from chia.wallet.derivation_record import DerivationRecord
35
+ from chia.wallet.did_wallet import did_wallet_puzzles
36
+ from chia.wallet.did_wallet.did_info import DIDInfo
37
+ from chia.wallet.lineage_proof import LineageProof
38
+ from chia.wallet.nft_wallet import nft_puzzles
39
+ from chia.wallet.nft_wallet.nft_info import NFTCoinInfo, NFTWalletInfo
40
+ from chia.wallet.nft_wallet.nft_puzzles import NFT_METADATA_UPDATER, create_ownership_layer_puzzle, get_metadata_and_phs
41
+ from chia.wallet.nft_wallet.uncurry_nft import NFTCoinData, UncurriedNFT
42
+ from chia.wallet.outer_puzzles import AssetType, construct_puzzle, match_puzzle, solve_puzzle
43
+ from chia.wallet.payment import Payment
44
+ from chia.wallet.puzzle_drivers import PuzzleInfo, Solver
45
+ from chia.wallet.puzzles.p2_delegated_puzzle_or_hidden_puzzle import (
46
+ DEFAULT_HIDDEN_PUZZLE_HASH,
47
+ calculate_synthetic_secret_key,
48
+ puzzle_for_pk,
49
+ )
50
+ from chia.wallet.trading.offer import OFFER_MOD, OFFER_MOD_HASH, NotarizedPayment, Offer
51
+ from chia.wallet.transaction_record import TransactionRecord
52
+ from chia.wallet.uncurried_puzzle import uncurry_puzzle
53
+ from chia.wallet.util.compute_memos import compute_memos
54
+ from chia.wallet.util.transaction_type import TransactionType
55
+ from chia.wallet.util.wallet_types import WalletType
56
+ from chia.wallet.wallet import Wallet
57
+ from chia.wallet.wallet_action_scope import WalletActionScope
58
+ from chia.wallet.wallet_coin_record import WalletCoinRecord
59
+ from chia.wallet.wallet_info import WalletInfo
60
+ from chia.wallet.wallet_nft_store import WalletNftStore
61
+ from chia.wallet.wallet_protocol import GSTOptionalArgs, WalletProtocol
62
+ from chia.wallet.wallet_spend_bundle import WalletSpendBundle
63
+
64
+ _T_NFTWallet = TypeVar("_T_NFTWallet", bound="NFTWallet")
65
+
66
+
67
+ class NFTWallet:
68
+ if TYPE_CHECKING:
69
+ _protocol_check: ClassVar[WalletProtocol[NFTCoinData]] = cast("NFTWallet", None)
70
+
71
+ wallet_state_manager: Any
72
+ log: logging.Logger
73
+ wallet_info: WalletInfo
74
+ nft_wallet_info: NFTWalletInfo
75
+ standard_wallet: Wallet
76
+ wallet_id: int
77
+ nft_store: WalletNftStore
78
+
79
+ @property
80
+ def did_id(self) -> Optional[bytes32]:
81
+ return self.nft_wallet_info.did_id
82
+
83
+ @classmethod
84
+ async def create_new_nft_wallet(
85
+ cls: type[_T_NFTWallet],
86
+ wallet_state_manager: Any,
87
+ wallet: Wallet,
88
+ did_id: Optional[bytes32] = None,
89
+ name: Optional[str] = None,
90
+ ) -> _T_NFTWallet:
91
+ """
92
+ This must be called under the wallet state manager lock
93
+ """
94
+ self = cls()
95
+ self.standard_wallet = wallet
96
+ if name is None:
97
+ name = "NFT Wallet"
98
+ self.log = logging.getLogger(name if name else __name__)
99
+ self.wallet_state_manager = wallet_state_manager
100
+ self.nft_wallet_info = NFTWalletInfo(did_id)
101
+ info_as_string = json.dumps(self.nft_wallet_info.to_json_dict())
102
+ self.wallet_info = await wallet_state_manager.user_store.create_wallet(
103
+ name, uint32(WalletType.NFT.value), info_as_string
104
+ )
105
+ self.wallet_id = self.wallet_info.id
106
+ self.nft_store = wallet_state_manager.nft_store
107
+ self.log.debug("NFT wallet id: %r and standard wallet id: %r", self.wallet_id, self.standard_wallet.wallet_id)
108
+
109
+ await self.wallet_state_manager.add_new_wallet(self)
110
+ self.log.debug("Generated a new NFT wallet: %s", self.__dict__)
111
+ return self
112
+
113
+ @classmethod
114
+ async def create(
115
+ cls: type[_T_NFTWallet],
116
+ wallet_state_manager: Any,
117
+ wallet: Wallet,
118
+ wallet_info: WalletInfo,
119
+ name: Optional[str] = None,
120
+ ) -> _T_NFTWallet:
121
+ self = cls()
122
+ self.log = logging.getLogger(name if name else __name__)
123
+ self.wallet_state_manager = wallet_state_manager
124
+ self.wallet_info = wallet_info
125
+ self.wallet_id = wallet_info.id
126
+ self.standard_wallet = wallet
127
+ self.wallet_info = wallet_info
128
+ self.nft_store = wallet_state_manager.nft_store
129
+ self.nft_wallet_info = NFTWalletInfo.from_json_dict(json.loads(wallet_info.data))
130
+ return self
131
+
132
+ @classmethod
133
+ def type(cls) -> WalletType:
134
+ return WalletType.NFT
135
+
136
+ def id(self) -> uint32:
137
+ return self.wallet_info.id
138
+
139
+ def get_did(self) -> Optional[bytes32]:
140
+ return self.did_id
141
+
142
+ async def get_confirmed_balance(self, record_list: Optional[set[WalletCoinRecord]] = None) -> uint128:
143
+ """The NFT wallet doesn't really have a balance."""
144
+ return uint128(0)
145
+
146
+ async def get_unconfirmed_balance(self, record_list: Optional[set[WalletCoinRecord]] = None) -> uint128:
147
+ """The NFT wallet doesn't really have a balance."""
148
+ return uint128(0)
149
+
150
+ async def get_spendable_balance(self, unspent_records: Optional[set[WalletCoinRecord]] = None) -> uint128:
151
+ """The NFT wallet doesn't really have a balance."""
152
+ return uint128(0)
153
+
154
+ async def get_pending_change_balance(self) -> uint64:
155
+ return uint64(0)
156
+
157
+ async def get_max_send_amount(self, records: Optional[set[WalletCoinRecord]] = None) -> uint128:
158
+ """This is the confirmed balance, which we set to 0 as the NFT wallet doesn't have one."""
159
+ return uint128(0)
160
+
161
+ async def get_nft_coin_by_id(self, nft_coin_id: bytes32) -> NFTCoinInfo:
162
+ nft_coin = await self.nft_store.get_nft_by_coin_id(nft_coin_id)
163
+ if nft_coin is None:
164
+ raise KeyError(f"Couldn't find coin with id: {nft_coin_id}")
165
+ return nft_coin
166
+
167
+ async def coin_added(
168
+ self, coin: Coin, height: uint32, peer: WSChiaConnection, parent_coin_data: Optional[NFTCoinData]
169
+ ) -> None:
170
+ """Notification from wallet state manager that wallet has been received."""
171
+ self.log.info(f"NFT wallet %s has been notified that {coin} was added", self.get_name())
172
+ if await self.nft_store.exists(coin.name()):
173
+ # already added
174
+ return
175
+ assert isinstance(parent_coin_data, NFTCoinData), f"Invalid NFT coin data: {parent_coin_data}"
176
+ await self.puzzle_solution_received(coin, parent_coin_data, peer)
177
+
178
+ async def puzzle_solution_received(self, coin: Coin, data: NFTCoinData, peer: WSChiaConnection) -> None:
179
+ self.log.debug("Puzzle solution received to wallet: %s", self.wallet_info)
180
+ # At this point, the puzzle must be a NFT puzzle.
181
+ # This method will be called only when the wallet state manager uncurried this coin as a NFT puzzle.
182
+
183
+ uncurried_nft: UncurriedNFT = data.uncurried_nft
184
+ self.log.debug(
185
+ "found the info for NFT coin %s %s %s",
186
+ coin.name().hex(),
187
+ uncurried_nft.inner_puzzle,
188
+ uncurried_nft.singleton_struct,
189
+ )
190
+ singleton_id = uncurried_nft.singleton_launcher_id
191
+ parent_inner_puzhash = uncurried_nft.nft_state_layer.get_tree_hash()
192
+ metadata, p2_puzzle_hash = get_metadata_and_phs(uncurried_nft, data.parent_coin_spend.solution)
193
+ self.log.debug("Got back puzhash from solution: %s", p2_puzzle_hash)
194
+ self.log.debug("Got back updated metadata: %s", metadata)
195
+ derivation_record: Optional[
196
+ DerivationRecord
197
+ ] = await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(p2_puzzle_hash)
198
+ self.log.debug("Record for %s is: %s", p2_puzzle_hash, derivation_record)
199
+ if derivation_record is None:
200
+ self.log.debug("Not our NFT, pointing to %s, skipping", p2_puzzle_hash)
201
+ return
202
+ p2_puzzle = puzzle_for_pk(derivation_record.pubkey)
203
+ launcher_coin_states: list[CoinState] = await self.wallet_state_manager.wallet_node.get_coin_state(
204
+ [singleton_id], peer=peer
205
+ )
206
+ assert (
207
+ launcher_coin_states is not None
208
+ and len(launcher_coin_states) == 1
209
+ and launcher_coin_states[0].spent_height is not None
210
+ )
211
+ mint_height: uint32 = uint32(launcher_coin_states[0].spent_height)
212
+ minter_did = None
213
+ if uncurried_nft.supports_did:
214
+ inner_puzzle = nft_puzzles.recurry_nft_puzzle(
215
+ uncurried_nft, data.parent_coin_spend.solution.to_program(), p2_puzzle
216
+ )
217
+ minter_did = await self.wallet_state_manager.get_minter_did(launcher_coin_states[0].coin, peer)
218
+ else:
219
+ inner_puzzle = p2_puzzle
220
+ child_puzzle: Program = nft_puzzles.create_full_puzzle(
221
+ singleton_id,
222
+ Program.to(metadata),
223
+ bytes32(uncurried_nft.metadata_updater_hash.as_atom()),
224
+ inner_puzzle,
225
+ )
226
+ self.log.debug(
227
+ "Created NFT full puzzle with inner: %s",
228
+ nft_puzzles.create_full_puzzle_with_nft_puzzle(singleton_id, uncurried_nft.inner_puzzle),
229
+ )
230
+ child_puzzle_hash = child_puzzle.get_tree_hash()
231
+ for new_coin in compute_additions(data.parent_coin_spend):
232
+ self.log.debug(
233
+ "Comparing addition: %s with %s, amount: %s ",
234
+ new_coin.puzzle_hash,
235
+ child_puzzle_hash,
236
+ new_coin.amount,
237
+ )
238
+ if new_coin.puzzle_hash == child_puzzle_hash:
239
+ child_coin = new_coin
240
+ break
241
+ else:
242
+ raise ValueError("Couldn't generate child puzzle for NFT")
243
+
244
+ self.log.info("Adding a new NFT to wallet: %s", child_coin)
245
+ # all is well, lets add NFT to our local db
246
+ parent_coin = data.parent_coin_state.coin
247
+ confirmed_height = (
248
+ None if data.parent_coin_state.spent_height is None else uint32(data.parent_coin_state.spent_height)
249
+ )
250
+
251
+ if confirmed_height is None:
252
+ raise ValueError("Error finding parent")
253
+
254
+ await self.add_coin(
255
+ child_coin,
256
+ singleton_id,
257
+ child_puzzle,
258
+ LineageProof(parent_coin.parent_coin_info, parent_inner_puzhash, uint64(parent_coin.amount)),
259
+ mint_height,
260
+ minter_did,
261
+ confirmed_height,
262
+ )
263
+
264
+ async def add_coin(
265
+ self,
266
+ coin: Coin,
267
+ nft_id: bytes32,
268
+ puzzle: Program,
269
+ lineage_proof: LineageProof,
270
+ mint_height: uint32,
271
+ minter_did: Optional[bytes32],
272
+ confirmed_height: uint32,
273
+ ) -> None:
274
+ new_nft = NFTCoinInfo(nft_id, coin, lineage_proof, puzzle, mint_height, minter_did, confirmed_height)
275
+ await self.wallet_state_manager.nft_store.save_nft(self.id(), self.get_did(), new_nft)
276
+ await self.wallet_state_manager.add_interested_coin_ids([coin.name()])
277
+ self.wallet_state_manager.state_changed("nft_coin_added", self.wallet_info.id)
278
+
279
+ async def remove_coin(self, coin: Coin, height: uint32) -> None:
280
+ nft_coin_info = await self.nft_store.get_nft_by_coin_id(coin.name())
281
+ if nft_coin_info:
282
+ await self.nft_store.delete_nft_by_coin_id(coin.name(), height)
283
+ self.wallet_state_manager.state_changed("nft_coin_removed", self.wallet_info.id)
284
+ num = await self.get_nft_count()
285
+ if num == 0 and self.did_id is not None:
286
+ # Check if the wallet owns the DID
287
+ for did_wallet in await self.wallet_state_manager.get_all_wallet_info_entries(
288
+ wallet_type=WalletType.DECENTRALIZED_ID
289
+ ):
290
+ did_wallet_info: DIDInfo = DIDInfo.from_json_dict(json.loads(did_wallet.data))
291
+ assert did_wallet_info.origin_coin is not None
292
+ if did_wallet_info.origin_coin.name() == self.did_id:
293
+ return
294
+ self.log.info(f"No NFT, deleting wallet {self.wallet_info.name} ...")
295
+ await self.wallet_state_manager.delete_wallet(self.wallet_info.id)
296
+ self.wallet_state_manager.wallets.pop(self.wallet_info.id)
297
+ else:
298
+ self.log.info("Tried removing NFT coin that doesn't exist: %s", coin.name())
299
+
300
+ async def get_did_approval_info(
301
+ self,
302
+ nft_ids: list[bytes32],
303
+ action_scope: WalletActionScope,
304
+ did_id: Optional[bytes32] = None,
305
+ ) -> bytes32:
306
+ """Get DID spend with announcement created we need to transfer NFT with did with current inner hash of DID
307
+
308
+ We also store `did_id` and then iterate to find the did wallet as we'd otherwise have to subscribe to
309
+ any changes to DID wallet and storing wallet_id is not guaranteed to be consistent on wallet crash/reset.
310
+ """
311
+ if did_id is None:
312
+ did_id = self.did_id
313
+ did_inner_hash: bytes32
314
+ for _, wallet in self.wallet_state_manager.wallets.items():
315
+ self.log.debug("Checking wallet type %s", wallet.type())
316
+ if wallet.type() == WalletType.DECENTRALIZED_ID:
317
+ self.log.debug("Found a DID wallet, checking did: %r == %r", wallet.get_my_DID(), did_id)
318
+ if bytes32.fromhex(wallet.get_my_DID()) == did_id:
319
+ self.log.debug("Creating announcement from DID for nft_ids: %s", nft_ids)
320
+ await wallet.create_message_spend(
321
+ action_scope, extra_conditions=(CreatePuzzleAnnouncement(id) for id in nft_ids)
322
+ )
323
+ did_inner_hash = wallet.did_info.current_inner.get_tree_hash()
324
+ break
325
+ else:
326
+ raise ValueError(f"Missing DID Wallet for did_id: {did_id}")
327
+ return did_inner_hash
328
+
329
+ async def generate_new_nft(
330
+ self,
331
+ metadata: Program,
332
+ action_scope: WalletActionScope,
333
+ target_puzzle_hash: Optional[bytes32] = None,
334
+ royalty_puzzle_hash: Optional[bytes32] = None,
335
+ percentage: uint16 = uint16(0),
336
+ did_id: Optional[bytes] = None,
337
+ fee: uint64 = uint64(0),
338
+ extra_conditions: tuple[Condition, ...] = tuple(),
339
+ ) -> bytes32:
340
+ """
341
+ This must be called under the wallet state manager lock
342
+ """
343
+ if self.did_id is not None and did_id is None:
344
+ # For a DID enabled NFT wallet it cannot mint NFT0. Mint NFT1 instead.
345
+ did_id = self.did_id
346
+ amount = uint64(1)
347
+ # ensure percentage is uint16
348
+ try:
349
+ percentage = uint16(percentage)
350
+ except ValueError:
351
+ raise ValueError("Percentage must be lower than 655%")
352
+ coins = await self.standard_wallet.select_coins(uint64(amount + fee), action_scope)
353
+ if coins is None:
354
+ return None
355
+ origin = coins.copy().pop()
356
+ genesis_launcher_puz = nft_puzzles.LAUNCHER_PUZZLE
357
+ # nft_id == singleton_id == launcher_id == launcher_coin.name()
358
+ launcher_coin = Coin(origin.name(), nft_puzzles.LAUNCHER_PUZZLE_HASH, uint64(amount))
359
+ self.log.debug("Generating NFT with launcher coin %s and metadata: %s", launcher_coin, metadata)
360
+
361
+ p2_inner_puzzle = await self.standard_wallet.get_puzzle(new=not action_scope.config.tx_config.reuse_puzhash)
362
+ if not target_puzzle_hash:
363
+ target_puzzle_hash = p2_inner_puzzle.get_tree_hash()
364
+ self.log.debug("Attempt to generate a new NFT to %s", target_puzzle_hash.hex())
365
+ if did_id is not None:
366
+ self.log.debug("Creating provenant NFT")
367
+ # eve coin DID can be set to whatever so we keep it empty
368
+ # WARNING: wallets should always ignore DID value for eve coins as they can be set
369
+ # to any DID without approval
370
+ inner_puzzle = create_ownership_layer_puzzle(
371
+ launcher_coin.name(), b"", p2_inner_puzzle, percentage, royalty_puzzle_hash=royalty_puzzle_hash
372
+ )
373
+ self.log.debug("Got back ownership inner puzzle: %s", inner_puzzle)
374
+ else:
375
+ self.log.debug("Creating standard NFT")
376
+ inner_puzzle = p2_inner_puzzle
377
+
378
+ # singleton eve puzzle
379
+ eve_fullpuz = nft_puzzles.create_full_puzzle(
380
+ launcher_coin.name(), metadata, NFT_METADATA_UPDATER.get_tree_hash(), inner_puzzle
381
+ )
382
+ eve_fullpuz_hash = eve_fullpuz.get_tree_hash()
383
+ # launcher announcement
384
+ announcement_message = Program.to([eve_fullpuz_hash, amount, []]).get_tree_hash()
385
+
386
+ self.log.debug(
387
+ "Creating transaction for launcher: %s and other coins: %s (%s)", origin, coins, announcement_message
388
+ )
389
+ # store the launcher transaction in the wallet state
390
+ await self.standard_wallet.generate_signed_transaction(
391
+ uint64(amount),
392
+ nft_puzzles.LAUNCHER_PUZZLE_HASH,
393
+ action_scope,
394
+ fee,
395
+ coins,
396
+ None,
397
+ origin_id=origin.name(),
398
+ extra_conditions=(
399
+ *extra_conditions,
400
+ AssertCoinAnnouncement(asserted_id=launcher_coin.name(), asserted_msg=announcement_message),
401
+ ),
402
+ )
403
+ genesis_launcher_solution = Program.to([eve_fullpuz_hash, amount, []])
404
+
405
+ # launcher spend to generate the singleton
406
+ launcher_cs = make_spend(launcher_coin, genesis_launcher_puz, genesis_launcher_solution)
407
+ launcher_sb = WalletSpendBundle([launcher_cs], AugSchemeMPL.aggregate([]))
408
+
409
+ eve_coin = Coin(launcher_coin.name(), eve_fullpuz_hash, uint64(amount))
410
+
411
+ async with action_scope.use() as interface:
412
+ interface.side_effects.extra_spends.append(launcher_sb)
413
+
414
+ # Create inner solution for eve spend
415
+ did_inner_hash = b""
416
+ if did_id is not None:
417
+ if did_id != b"":
418
+ did_inner_hash = await self.get_did_approval_info([launcher_coin.name()], action_scope)
419
+ nft_coin = NFTCoinInfo(
420
+ nft_id=launcher_coin.name(),
421
+ coin=eve_coin,
422
+ lineage_proof=LineageProof(parent_name=launcher_coin.parent_coin_info, amount=uint64(launcher_coin.amount)),
423
+ full_puzzle=eve_fullpuz,
424
+ mint_height=uint32(0),
425
+ minter_did=bytes32(did_id) if did_id is not None and did_id != b"" else None,
426
+ )
427
+ # Don't set fee, it is covered in the tx_record
428
+ await self.generate_signed_transaction(
429
+ [uint64(eve_coin.amount)],
430
+ [target_puzzle_hash],
431
+ action_scope,
432
+ nft_coin=nft_coin,
433
+ new_owner=did_id,
434
+ new_did_inner_hash=did_inner_hash,
435
+ memos=[[target_puzzle_hash]],
436
+ )
437
+
438
+ return launcher_coin.name()
439
+
440
+ async def update_metadata(
441
+ self,
442
+ nft_coin_info: NFTCoinInfo,
443
+ key: str,
444
+ uri: str,
445
+ action_scope: WalletActionScope,
446
+ fee: uint64 = uint64(0),
447
+ extra_conditions: tuple[Condition, ...] = tuple(),
448
+ ) -> None:
449
+ uncurried_nft = UncurriedNFT.uncurry(*nft_coin_info.full_puzzle.uncurry())
450
+ assert uncurried_nft is not None
451
+ puzzle_hash = uncurried_nft.p2_puzzle.get_tree_hash()
452
+
453
+ self.log.info(
454
+ "Attempting to add urls to NFT coin %s in the metadata: %s",
455
+ nft_coin_info.coin.name(),
456
+ uncurried_nft.metadata,
457
+ )
458
+ await self.generate_signed_transaction(
459
+ [uint64(nft_coin_info.coin.amount)],
460
+ [puzzle_hash],
461
+ action_scope,
462
+ fee,
463
+ {nft_coin_info.coin},
464
+ metadata_update=(key, uri),
465
+ extra_conditions=extra_conditions,
466
+ )
467
+ await self.update_coin_status(nft_coin_info.coin.name(), True)
468
+ self.wallet_state_manager.state_changed("nft_coin_updated", self.wallet_info.id)
469
+
470
+ async def get_current_nfts(self, start_index: int = 0, count: int = 50) -> list[NFTCoinInfo]:
471
+ return await self.nft_store.get_nft_list(wallet_id=self.id(), start_index=start_index, count=count)
472
+
473
+ async def get_nft_count(self) -> int:
474
+ return await self.nft_store.count(wallet_id=self.id())
475
+
476
+ async def is_empty(self) -> bool:
477
+ return await self.nft_store.is_empty(wallet_id=self.id())
478
+
479
+ async def update_coin_status(self, coin_id: bytes32, pending_transaction: bool) -> None:
480
+ await self.nft_store.update_pending_transaction(coin_id, pending_transaction)
481
+
482
+ async def save_info(self, nft_info: NFTWalletInfo) -> None:
483
+ self.nft_wallet_info = nft_info
484
+ current_info = self.wallet_info
485
+ data_str = json.dumps(nft_info.to_json_dict())
486
+ wallet_info = WalletInfo(current_info.id, current_info.name, current_info.type, data_str)
487
+ self.wallet_info = wallet_info
488
+ await self.wallet_state_manager.user_store.update_wallet(wallet_info)
489
+
490
+ async def convert_puzzle_hash(self, puzhash: bytes32) -> bytes32:
491
+ return puzhash
492
+
493
+ async def get_nft(self, launcher_id: bytes32) -> Optional[NFTCoinInfo]:
494
+ return await self.nft_store.get_nft_by_id(launcher_id)
495
+
496
+ async def get_puzzle_info(self, nft_id: bytes32) -> PuzzleInfo:
497
+ nft_coin: Optional[NFTCoinInfo] = await self.get_nft(nft_id)
498
+ if nft_coin is None:
499
+ raise ValueError("An asset ID was specified that this wallet doesn't track")
500
+ puzzle_info: Optional[PuzzleInfo] = match_puzzle(uncurry_puzzle(nft_coin.full_puzzle))
501
+ if puzzle_info is None:
502
+ raise ValueError("Internal Error: NFT wallet is tracking a non NFT coin")
503
+ else:
504
+ return puzzle_info
505
+
506
+ async def sign_message(self, message: str, nft: NFTCoinInfo, mode: SigningMode) -> tuple[G1Element, G2Element]:
507
+ uncurried_nft = UncurriedNFT.uncurry(*nft.full_puzzle.uncurry())
508
+ if uncurried_nft is not None:
509
+ p2_puzzle = uncurried_nft.p2_puzzle
510
+ puzzle_hash = p2_puzzle.get_tree_hash()
511
+ private = await self.wallet_state_manager.get_private_key(puzzle_hash)
512
+ synthetic_secret_key = calculate_synthetic_secret_key(private, DEFAULT_HIDDEN_PUZZLE_HASH)
513
+ synthetic_pk = synthetic_secret_key.get_g1()
514
+ if mode == SigningMode.CHIP_0002_HEX_INPUT:
515
+ hex_message: bytes = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, bytes.fromhex(message))).get_tree_hash()
516
+ elif mode == SigningMode.BLS_MESSAGE_AUGMENTATION_UTF8_INPUT:
517
+ hex_message = bytes(message, "utf-8")
518
+ elif mode == SigningMode.BLS_MESSAGE_AUGMENTATION_HEX_INPUT:
519
+ hex_message = bytes.fromhex(message)
520
+ else:
521
+ hex_message = Program.to((CHIP_0002_SIGN_MESSAGE_PREFIX, message)).get_tree_hash()
522
+ return synthetic_pk, AugSchemeMPL.sign(synthetic_secret_key, hex_message)
523
+ else:
524
+ raise ValueError("Invalid NFT puzzle.")
525
+
526
+ async def get_coins_to_offer(
527
+ self,
528
+ nft_id: bytes32,
529
+ *args: Any,
530
+ **kwargs: Any,
531
+ ) -> set[Coin]:
532
+ nft_coin: Optional[NFTCoinInfo] = await self.get_nft(nft_id)
533
+ if nft_coin is None:
534
+ raise ValueError("An asset ID was specified that this wallet doesn't track")
535
+ return {nft_coin.coin}
536
+
537
+ async def match_puzzle_info(self, puzzle_driver: PuzzleInfo) -> bool:
538
+ return (
539
+ AssetType(puzzle_driver.type()) == AssetType.SINGLETON
540
+ and puzzle_driver.also() is not None
541
+ and AssetType(puzzle_driver.also().type()) == AssetType.METADATA # type: ignore
542
+ and puzzle_driver.also().also() is None # type: ignore
543
+ and await self.get_nft(puzzle_driver["launcher_id"]) is not None
544
+ )
545
+
546
+ @classmethod
547
+ async def create_from_puzzle_info(
548
+ cls: Any,
549
+ wallet_state_manager: Any,
550
+ wallet: Wallet,
551
+ puzzle_driver: PuzzleInfo,
552
+ name: Optional[str] = None,
553
+ ) -> Any:
554
+ # Off the bat we don't support multiple profile but when we do this will have to change
555
+ for wallet in wallet_state_manager.wallets.values():
556
+ if wallet.type() == WalletType.NFT.value:
557
+ return wallet
558
+
559
+ # TODO: These are not the arguments to this function yet but they will be
560
+ return await cls.create_new_nft_wallet(
561
+ wallet_state_manager,
562
+ wallet,
563
+ None,
564
+ name,
565
+ )
566
+
567
+ async def generate_signed_transaction(
568
+ self,
569
+ amounts: list[uint64],
570
+ puzzle_hashes: list[bytes32],
571
+ action_scope: WalletActionScope,
572
+ fee: uint64 = uint64(0),
573
+ coins: Optional[set[Coin]] = None,
574
+ memos: Optional[list[list[bytes]]] = None,
575
+ extra_conditions: tuple[Condition, ...] = tuple(),
576
+ **kwargs: Unpack[GSTOptionalArgs],
577
+ ) -> None:
578
+ nft_coin: Optional[NFTCoinInfo] = kwargs.get("nft_coin", None)
579
+ new_owner: Optional[bytes] = kwargs.get("new_owner", None)
580
+ new_did_inner_hash: Optional[bytes] = kwargs.get("new_did_inner_hash", None)
581
+ trade_prices_list: Optional[Program] = kwargs.get("trade_prices_list", None)
582
+ additional_bundles: list[WalletSpendBundle] = kwargs.get("additional_bundles", [])
583
+ metadata_update: Optional[tuple[str, str]] = kwargs.get("metadata_update", None)
584
+ if memos is None:
585
+ memos = [[] for _ in range(len(puzzle_hashes))]
586
+
587
+ if not (len(memos) == len(puzzle_hashes) == len(amounts)):
588
+ raise ValueError("Memos, puzzle_hashes, and amounts must have the same length")
589
+
590
+ payments = []
591
+ for amount, puzhash, memo_list in zip(amounts, puzzle_hashes, memos):
592
+ memos_with_hint: list[bytes] = [puzhash]
593
+ memos_with_hint.extend(memo_list)
594
+ payments.append(Payment(puzhash, amount, memos_with_hint))
595
+
596
+ payment_sum = sum(p.amount for p in payments)
597
+ unsigned_spend_bundle = await self.generate_unsigned_spendbundle(
598
+ payments,
599
+ action_scope,
600
+ fee,
601
+ coins=coins,
602
+ nft_coin=nft_coin,
603
+ new_owner=new_owner,
604
+ new_did_inner_hash=new_did_inner_hash,
605
+ trade_prices_list=trade_prices_list,
606
+ metadata_update=metadata_update,
607
+ extra_conditions=extra_conditions,
608
+ )
609
+ spend_bundle = WalletSpendBundle.aggregate([unsigned_spend_bundle, *additional_bundles])
610
+
611
+ async with action_scope.use() as interface:
612
+ other_tx_removals: set[Coin] = {
613
+ removal for tx in interface.side_effects.transactions for removal in tx.removals
614
+ }
615
+ other_tx_additions: set[Coin] = {
616
+ addition for tx in interface.side_effects.transactions for addition in tx.additions
617
+ }
618
+ tx = TransactionRecord(
619
+ confirmed_at_height=uint32(0),
620
+ created_at_time=uint64(int(time.time())),
621
+ to_puzzle_hash=puzzle_hashes[0],
622
+ amount=uint64(payment_sum),
623
+ fee_amount=fee,
624
+ confirmed=False,
625
+ sent=uint32(0),
626
+ spend_bundle=spend_bundle,
627
+ additions=list(set(spend_bundle.additions()) - other_tx_additions),
628
+ removals=list(set(spend_bundle.removals()) - other_tx_removals),
629
+ wallet_id=self.id(),
630
+ sent_to=[],
631
+ trade_id=None,
632
+ type=uint32(TransactionType.OUTGOING_TX.value),
633
+ name=spend_bundle.name(),
634
+ memos=list(compute_memos(spend_bundle).items()),
635
+ valid_times=parse_timelock_info(extra_conditions),
636
+ )
637
+
638
+ interface.side_effects.transactions.append(tx)
639
+
640
+ async def generate_unsigned_spendbundle(
641
+ self,
642
+ payments: list[Payment],
643
+ action_scope: WalletActionScope,
644
+ fee: uint64 = uint64(0),
645
+ coins: Optional[set[Coin]] = None,
646
+ new_owner: Optional[bytes] = None,
647
+ new_did_inner_hash: Optional[bytes] = None,
648
+ trade_prices_list: Optional[Program] = None,
649
+ metadata_update: Optional[tuple[str, str]] = None,
650
+ nft_coin: Optional[NFTCoinInfo] = None,
651
+ extra_conditions: tuple[Condition, ...] = tuple(),
652
+ ) -> WalletSpendBundle:
653
+ if nft_coin is None:
654
+ if coins is None or not len(coins) == 1:
655
+ # Make sure the user is specifying which specific NFT coin to use
656
+ raise ValueError("NFT spends require a single selected coin")
657
+ elif len(payments) > 1:
658
+ raise ValueError("NFTs can only be sent to one party")
659
+ nft_coin = await self.nft_store.get_nft_by_coin_id(coins.pop().name())
660
+ assert nft_coin
661
+
662
+ coin_name = nft_coin.coin.name()
663
+ if fee > 0:
664
+ await self.standard_wallet.create_tandem_xch_tx(
665
+ fee,
666
+ action_scope,
667
+ extra_conditions=(AssertCoinAnnouncement(asserted_id=coin_name, asserted_msg=coin_name),),
668
+ )
669
+
670
+ unft = UncurriedNFT.uncurry(*nft_coin.full_puzzle.uncurry())
671
+ assert unft is not None
672
+ if unft.supports_did:
673
+ if new_owner is None:
674
+ # If no new owner was specified and we're sending this to ourselves, let's not reset the DID
675
+ derivation_record: Optional[
676
+ DerivationRecord
677
+ ] = await self.wallet_state_manager.puzzle_store.get_derivation_record_for_puzzle_hash(
678
+ payments[0].puzzle_hash
679
+ )
680
+ if derivation_record is not None:
681
+ new_owner = unft.owner_did
682
+ extra_conditions = (
683
+ *extra_conditions,
684
+ UnknownCondition(
685
+ opcode=Program.to(-10),
686
+ args=[
687
+ Program.to(new_owner),
688
+ Program.to(trade_prices_list),
689
+ Program.to(new_did_inner_hash),
690
+ ],
691
+ ),
692
+ )
693
+ if metadata_update is not None:
694
+ extra_conditions = (
695
+ *extra_conditions,
696
+ UnknownCondition(
697
+ opcode=Program.to(-24),
698
+ args=[
699
+ NFT_METADATA_UPDATER,
700
+ Program.to(metadata_update),
701
+ ],
702
+ ),
703
+ )
704
+
705
+ innersol: Program = self.standard_wallet.make_solution(
706
+ primaries=payments,
707
+ conditions=(*extra_conditions, CreateCoinAnnouncement(coin_name)) if fee > 0 else extra_conditions,
708
+ )
709
+
710
+ if unft.supports_did:
711
+ innersol = Program.to([innersol])
712
+
713
+ nft_layer_solution = Program.to([innersol])
714
+ assert isinstance(nft_coin.lineage_proof, LineageProof)
715
+ singleton_solution = Program.to([nft_coin.lineage_proof.to_program(), nft_coin.coin.amount, nft_layer_solution])
716
+ coin_spend = make_spend(nft_coin.coin, nft_coin.full_puzzle, singleton_solution)
717
+
718
+ nft_spend_bundle = WalletSpendBundle([coin_spend], G2Element())
719
+
720
+ return nft_spend_bundle
721
+
722
+ @staticmethod
723
+ def royalty_calculation(
724
+ royalty_assets_dict: dict[Any, tuple[Any, uint16]],
725
+ fungible_asset_dict: dict[Any, uint64],
726
+ ) -> dict[Any, list[dict[str, Any]]]:
727
+ summary_dict: dict[Any, list[dict[str, Any]]] = {}
728
+ for id, royalty_info in royalty_assets_dict.items():
729
+ address, percentage = royalty_info
730
+ summary_dict[id] = []
731
+ for name, amount in fungible_asset_dict.items():
732
+ summary_dict[id].append(
733
+ {
734
+ "asset": name,
735
+ "address": address,
736
+ "amount": math.floor(math.floor(abs(amount) / len(royalty_assets_dict)) * (percentage / 10000)),
737
+ }
738
+ )
739
+
740
+ return summary_dict
741
+
742
+ @staticmethod
743
+ async def make_nft1_offer(
744
+ wallet_state_manager: Any,
745
+ offer_dict: dict[Optional[bytes32], int],
746
+ driver_dict: dict[bytes32, PuzzleInfo],
747
+ action_scope: WalletActionScope,
748
+ fee: uint64,
749
+ extra_conditions: tuple[Condition, ...],
750
+ ) -> Offer:
751
+ # First, let's take note of all the royalty enabled NFTs
752
+ royalty_nft_asset_dict: dict[bytes32, int] = {}
753
+ for asset, amount in offer_dict.items():
754
+ if asset is not None and driver_dict[asset].check_type( # check if asset is an Royalty Enabled NFT
755
+ [
756
+ AssetType.SINGLETON.value,
757
+ AssetType.METADATA.value,
758
+ AssetType.OWNERSHIP.value,
759
+ ]
760
+ ):
761
+ driver_dict[asset].info["also"]["also"]["owner"] = "()"
762
+ royalty_nft_asset_dict[asset] = amount
763
+
764
+ # Then, all of the things that trigger royalties
765
+ fungible_asset_dict: dict[Optional[bytes32], int] = {}
766
+ for asset, amount in offer_dict.items():
767
+ if asset is None or driver_dict[asset].type() != AssetType.SINGLETON.value:
768
+ fungible_asset_dict[asset] = amount
769
+
770
+ # Let's gather some information about the royalties
771
+ offer_side_royalty_split: int = 0
772
+ request_side_royalty_split: int = 0
773
+ for asset, amount in royalty_nft_asset_dict.items(): # requested non fungible items
774
+ if amount > 0:
775
+ request_side_royalty_split += 1
776
+ elif amount < 0:
777
+ offer_side_royalty_split += 1
778
+
779
+ trade_prices: list[tuple[uint64, bytes32]] = []
780
+ for asset, amount in fungible_asset_dict.items(): # requested fungible items
781
+ if amount > 0 and offer_side_royalty_split > 0:
782
+ settlement_ph: bytes32 = (
783
+ OFFER_MOD_HASH if asset is None else construct_puzzle(driver_dict[asset], OFFER_MOD).get_tree_hash()
784
+ )
785
+ trade_prices.append((uint64(math.floor(amount / offer_side_royalty_split)), settlement_ph))
786
+
787
+ required_royalty_info: list[tuple[bytes32, bytes32, uint16]] = [] # [(launcher_id, address, percentage)]
788
+ offered_royalty_percentages: dict[bytes32, uint16] = {}
789
+ for asset, amount in royalty_nft_asset_dict.items(): # royalty enabled NFTs
790
+ transfer_info = driver_dict[asset].also().also() # type: ignore
791
+ assert isinstance(transfer_info, PuzzleInfo)
792
+ royalty_percentage_raw = transfer_info["transfer_program"]["royalty_percentage"]
793
+ assert royalty_percentage_raw is not None
794
+ # clvm encodes large ints as bytes
795
+ if isinstance(royalty_percentage_raw, bytes):
796
+ royalty_percentage = int_from_bytes(royalty_percentage_raw)
797
+ else:
798
+ royalty_percentage = int(royalty_percentage_raw)
799
+ if amount > 0:
800
+ required_royalty_info.append(
801
+ (
802
+ asset,
803
+ bytes32(transfer_info["transfer_program"]["royalty_address"]),
804
+ uint16(royalty_percentage),
805
+ )
806
+ )
807
+ else:
808
+ offered_royalty_percentages[asset] = uint16(royalty_percentage)
809
+
810
+ royalty_payments: dict[Optional[bytes32], list[tuple[bytes32, Payment]]] = {}
811
+ for asset, amount in fungible_asset_dict.items(): # offered fungible items
812
+ if amount < 0 and request_side_royalty_split > 0:
813
+ payment_list: list[tuple[bytes32, Payment]] = []
814
+ for launcher_id, address, percentage in required_royalty_info:
815
+ extra_royalty_amount = uint64(
816
+ math.floor(math.floor(abs(amount) / request_side_royalty_split) * (percentage / 10000))
817
+ )
818
+ if extra_royalty_amount == abs(amount):
819
+ raise ValueError("Amount offered and amount paid in royalties are equal")
820
+ payment_list.append((launcher_id, Payment(address, extra_royalty_amount, [address])))
821
+ royalty_payments[asset] = payment_list
822
+
823
+ # Generate the requested_payments to be notarized
824
+ p2_ph = await wallet_state_manager.main_wallet.get_puzzle_hash(
825
+ new=not action_scope.config.tx_config.reuse_puzhash
826
+ )
827
+ requested_payments: dict[Optional[bytes32], list[Payment]] = {}
828
+ for asset, amount in offer_dict.items():
829
+ if amount > 0:
830
+ requested_payments[asset] = [Payment(p2_ph, uint64(amount), [p2_ph] if asset is not None else [])]
831
+
832
+ # Find all the coins we're offering
833
+ offered_coins_by_asset: dict[Optional[bytes32], set[Coin]] = {}
834
+ all_offered_coins: set[Coin] = set()
835
+ for asset, amount in offer_dict.items():
836
+ if amount < 0:
837
+ if asset is None:
838
+ wallet = wallet_state_manager.main_wallet
839
+ else:
840
+ wallet = await wallet_state_manager.get_wallet_for_asset_id(asset.hex())
841
+ if asset in royalty_payments:
842
+ royalty_amount: int = sum(p.amount for _, p in royalty_payments[asset])
843
+ else:
844
+ royalty_amount = 0
845
+ if asset is None:
846
+ coin_amount_needed: int = abs(amount) + royalty_amount + fee
847
+ else:
848
+ coin_amount_needed = abs(amount) + royalty_amount
849
+ offered_coins: set[Coin] = await wallet.get_coins_to_offer(asset, coin_amount_needed, action_scope)
850
+ if len(offered_coins) == 0:
851
+ raise ValueError(f"Did not have asset ID {asset.hex() if asset is not None else 'XCH'} to offer")
852
+ offered_coins_by_asset[asset] = offered_coins
853
+ all_offered_coins.update(offered_coins)
854
+
855
+ # Notarize the payments and get the announcements for the bundle
856
+ notarized_payments: dict[Optional[bytes32], list[NotarizedPayment]] = Offer.notarize_payments(
857
+ requested_payments, list(all_offered_coins)
858
+ )
859
+ announcements_to_assert: list[AssertPuzzleAnnouncement] = Offer.calculate_announcements(
860
+ notarized_payments, driver_dict
861
+ )
862
+ for asset, payments in royalty_payments.items():
863
+ if asset is None: # xch offer
864
+ offer_puzzle = OFFER_MOD
865
+ royalty_ph = OFFER_MOD_HASH
866
+ else:
867
+ offer_puzzle = construct_puzzle(driver_dict[asset], OFFER_MOD)
868
+ royalty_ph = offer_puzzle.get_tree_hash()
869
+ announcements_to_assert.extend(
870
+ [
871
+ AssertPuzzleAnnouncement(
872
+ asserted_ph=royalty_ph,
873
+ asserted_msg=Program.to((launcher_id, [p.as_condition_args()])).get_tree_hash(),
874
+ )
875
+ for launcher_id, p in payments
876
+ if p.amount > 0
877
+ ]
878
+ )
879
+
880
+ # Create all of the transactions
881
+ all_transactions: list[TransactionRecord] = []
882
+ additional_bundles: list[WalletSpendBundle] = []
883
+ # standard pays the fee if possible
884
+ fee_left_to_pay: uint64 = uint64(0) if None in offer_dict and offer_dict[None] < 0 else fee
885
+
886
+ for asset, amount in offer_dict.items():
887
+ if amount < 0:
888
+ if asset is None:
889
+ wallet = wallet_state_manager.main_wallet
890
+ else:
891
+ wallet = await wallet_state_manager.get_wallet_for_asset_id(asset.hex())
892
+
893
+ # First, sending all the coins to the OFFER_MOD
894
+ async with wallet_state_manager.new_action_scope(
895
+ action_scope.config.tx_config, push=False
896
+ ) as inner_action_scope:
897
+ if wallet.type() == WalletType.STANDARD_WALLET:
898
+ payments = royalty_payments[asset] if asset in royalty_payments else []
899
+ payment_sum = sum(p.amount for _, p in payments)
900
+ await wallet.generate_signed_transaction(
901
+ abs(amount),
902
+ OFFER_MOD_HASH,
903
+ inner_action_scope,
904
+ primaries=[Payment(OFFER_MOD_HASH, uint64(payment_sum))] if payment_sum > 0 else [],
905
+ fee=fee,
906
+ coins=offered_coins_by_asset[asset],
907
+ extra_conditions=(*extra_conditions, *announcements_to_assert),
908
+ )
909
+ elif asset not in fungible_asset_dict:
910
+ assert asset is not None
911
+ await wallet.generate_signed_transaction(
912
+ [abs(amount)],
913
+ [OFFER_MOD_HASH],
914
+ inner_action_scope,
915
+ fee=fee_left_to_pay,
916
+ coins=offered_coins_by_asset[asset],
917
+ trade_prices_list=[
918
+ list(price)
919
+ for price in trade_prices
920
+ if math.floor(price[0] * (offered_royalty_percentages[asset] / 10000)) != 0
921
+ ],
922
+ extra_conditions=(*extra_conditions, *announcements_to_assert),
923
+ )
924
+ else:
925
+ payments = royalty_payments[asset] if asset in royalty_payments else []
926
+ await wallet.generate_signed_transaction(
927
+ [abs(amount)] + ([sum(p.amount for _, p in payments)] if payments != [] else []),
928
+ [OFFER_MOD_HASH] + ([OFFER_MOD_HASH] if payments != [] else []),
929
+ inner_action_scope,
930
+ fee=fee_left_to_pay,
931
+ coins=offered_coins_by_asset[asset],
932
+ extra_conditions=(*extra_conditions, *announcements_to_assert),
933
+ )
934
+ all_transactions.extend(inner_action_scope.side_effects.transactions)
935
+ fee_left_to_pay = uint64(0)
936
+ extra_conditions = tuple()
937
+
938
+ # Then, adding in the spends for the royalty offer mod
939
+ if asset in fungible_asset_dict:
940
+ # Create a coin_spend for the royalty payout from OFFER MOD
941
+
942
+ # Skip it if we're paying 0 royalties
943
+ payments = royalty_payments[asset] if asset in royalty_payments else []
944
+ if sum(p.amount for _, p in payments) == 0:
945
+ continue
946
+
947
+ # We cannot create coins with the same puzzle hash and amount
948
+ # So if there's multiple NFTs with the same royalty puzhash/percentage, we must create multiple
949
+ # generations of offer coins
950
+ royalty_coin: Optional[Coin] = None
951
+ parent_spend: Optional[CoinSpend] = None
952
+ while True:
953
+ duplicate_payments: list[tuple[bytes32, Payment]] = []
954
+ deduped_payment_list: list[tuple[bytes32, Payment]] = []
955
+ for launcher_id, payment in payments:
956
+ if payment in [p for _, p in deduped_payment_list]:
957
+ duplicate_payments.append((launcher_id, payment))
958
+ else:
959
+ deduped_payment_list.append((launcher_id, payment))
960
+
961
+ # ((nft_launcher_id . ((ROYALTY_ADDRESS, royalty_amount, memos) ...)))
962
+ inner_royalty_sol = Program.to(
963
+ [
964
+ (launcher_id, [payment.as_condition_args()])
965
+ for launcher_id, payment in deduped_payment_list
966
+ ]
967
+ )
968
+ if duplicate_payments != []:
969
+ inner_royalty_sol = Program.to(
970
+ (
971
+ None,
972
+ [
973
+ Payment(
974
+ OFFER_MOD_HASH,
975
+ uint64(sum(p.amount for _, p in duplicate_payments)),
976
+ ).as_condition_args()
977
+ ],
978
+ )
979
+ ).cons(inner_royalty_sol)
980
+
981
+ if asset is None: # xch offer
982
+ offer_puzzle = OFFER_MOD
983
+ royalty_ph = OFFER_MOD_HASH
984
+ else:
985
+ offer_puzzle = construct_puzzle(driver_dict[asset], OFFER_MOD)
986
+ royalty_ph = offer_puzzle.get_tree_hash()
987
+ if royalty_coin is None:
988
+ for tx in inner_action_scope.side_effects.transactions:
989
+ if tx.spend_bundle is not None:
990
+ for coin in tx.spend_bundle.additions():
991
+ royalty_payment_amount: int = sum(p.amount for _, p in payments)
992
+ if coin.amount == royalty_payment_amount and coin.puzzle_hash == royalty_ph:
993
+ royalty_coin = coin
994
+ parent_spend = next(
995
+ cs
996
+ for cs in tx.spend_bundle.coin_spends
997
+ if cs.coin.name() == royalty_coin.parent_coin_info
998
+ )
999
+ break
1000
+ else:
1001
+ continue
1002
+ break
1003
+ assert royalty_coin is not None
1004
+ assert parent_spend is not None
1005
+ if asset is None: # If XCH
1006
+ royalty_sol = inner_royalty_sol
1007
+ else:
1008
+ # call our drivers to solve the puzzle
1009
+ royalty_coin_hex = (
1010
+ "0x"
1011
+ + royalty_coin.parent_coin_info.hex()
1012
+ + royalty_coin.puzzle_hash.hex()
1013
+ + uint64(royalty_coin.amount).stream_to_bytes().hex()
1014
+ )
1015
+ parent_spend_hex: str = "0x" + bytes(parent_spend).hex()
1016
+ solver = Solver(
1017
+ {
1018
+ "coin": royalty_coin_hex,
1019
+ "parent_spend": parent_spend_hex,
1020
+ "siblings": "()",
1021
+ "sibling_spends": "()",
1022
+ "sibling_puzzles": "()",
1023
+ "sibling_solutions": "()",
1024
+ }
1025
+ )
1026
+ royalty_sol = solve_puzzle(driver_dict[asset], solver, OFFER_MOD, inner_royalty_sol)
1027
+
1028
+ new_coin_spend = make_spend(royalty_coin, offer_puzzle, royalty_sol)
1029
+ additional_bundles.append(WalletSpendBundle([new_coin_spend], G2Element()))
1030
+
1031
+ if duplicate_payments != []:
1032
+ payments = duplicate_payments
1033
+ royalty_coin = next(
1034
+ c for c in compute_additions(new_coin_spend) if c.puzzle_hash == royalty_ph
1035
+ )
1036
+ parent_spend = new_coin_spend
1037
+ continue
1038
+ else:
1039
+ break
1040
+
1041
+ # Finally, assemble the tx records properly
1042
+ txs_bundle = WalletSpendBundle.aggregate(
1043
+ [tx.spend_bundle for tx in all_transactions if tx.spend_bundle is not None]
1044
+ )
1045
+ aggregate_bundle = WalletSpendBundle.aggregate([txs_bundle, *additional_bundles])
1046
+ offer = Offer(notarized_payments, aggregate_bundle, driver_dict)
1047
+ async with action_scope.use() as interface:
1048
+ interface.side_effects.transactions.extend(all_transactions)
1049
+
1050
+ return offer
1051
+
1052
+ async def set_bulk_nft_did(
1053
+ self,
1054
+ nft_list: list[NFTCoinInfo],
1055
+ did_id: bytes,
1056
+ action_scope: WalletActionScope,
1057
+ fee: uint64 = uint64(0),
1058
+ announcement_ids: list[bytes32] = [],
1059
+ extra_conditions: tuple[Condition, ...] = tuple(),
1060
+ ) -> None:
1061
+ self.log.debug("Setting NFT DID with parameters: nft=%s did=%s", nft_list, did_id)
1062
+ nft_ids = []
1063
+ first = True
1064
+ for nft_coin_info in nft_list:
1065
+ nft_ids.append(nft_coin_info.nft_id)
1066
+ if did_id != b"" and len(announcement_ids) > 0:
1067
+ await self.get_did_approval_info(announcement_ids, action_scope, bytes32(did_id))
1068
+
1069
+ for _, wallet in self.wallet_state_manager.wallets.items():
1070
+ if wallet.type() == WalletType.DECENTRALIZED_ID:
1071
+ if bytes32.fromhex(wallet.get_my_DID()) == did_id:
1072
+ did_inner_hash = wallet.did_info.current_inner.get_tree_hash()
1073
+ break
1074
+ else:
1075
+ raise ValueError(f"No DID wallet with id: {did_id.hex()}")
1076
+
1077
+ for nft_coin_info in nft_list:
1078
+ unft = UncurriedNFT.uncurry(*nft_coin_info.full_puzzle.uncurry())
1079
+ assert unft is not None
1080
+ puzzle_hashes_to_sign = [unft.p2_puzzle.get_tree_hash()]
1081
+ if not first:
1082
+ fee = uint64(0)
1083
+ extra_conditions = tuple()
1084
+ await self.generate_signed_transaction(
1085
+ [uint64(nft_coin_info.coin.amount)],
1086
+ puzzle_hashes_to_sign,
1087
+ action_scope,
1088
+ fee,
1089
+ {nft_coin_info.coin},
1090
+ new_owner=did_id,
1091
+ new_did_inner_hash=did_inner_hash,
1092
+ extra_conditions=extra_conditions,
1093
+ )
1094
+ first = False
1095
+
1096
+ async def bulk_transfer_nft(
1097
+ self,
1098
+ nft_list: list[NFTCoinInfo],
1099
+ puzzle_hash: bytes32,
1100
+ action_scope: WalletActionScope,
1101
+ fee: uint64 = uint64(0),
1102
+ extra_conditions: tuple[Condition, ...] = tuple(),
1103
+ ) -> None:
1104
+ self.log.debug("Transfer NFTs %s to %s", nft_list, puzzle_hash.hex())
1105
+ first = True
1106
+
1107
+ for nft_coin_info in nft_list:
1108
+ if not first:
1109
+ fee = uint64(0)
1110
+ extra_conditions = tuple()
1111
+ await self.generate_signed_transaction(
1112
+ [uint64(nft_coin_info.coin.amount)],
1113
+ [puzzle_hash],
1114
+ action_scope,
1115
+ coins={nft_coin_info.coin},
1116
+ fee=fee,
1117
+ new_owner=b"",
1118
+ new_did_inner_hash=b"",
1119
+ extra_conditions=extra_conditions,
1120
+ )
1121
+ first = False
1122
+
1123
+ async def set_nft_did(
1124
+ self,
1125
+ nft_coin_info: NFTCoinInfo,
1126
+ did_id: bytes,
1127
+ action_scope: WalletActionScope,
1128
+ fee: uint64 = uint64(0),
1129
+ extra_conditions: tuple[Condition, ...] = tuple(),
1130
+ ) -> None:
1131
+ self.log.debug("Setting NFT DID with parameters: nft=%s did=%s", nft_coin_info, did_id)
1132
+ unft = UncurriedNFT.uncurry(*nft_coin_info.full_puzzle.uncurry())
1133
+ assert unft is not None
1134
+ nft_id = unft.singleton_launcher_id
1135
+ puzzle_hashes_to_sign = [unft.p2_puzzle.get_tree_hash()]
1136
+ did_inner_hash = b""
1137
+ if did_id != b"":
1138
+ did_inner_hash = await self.get_did_approval_info([nft_id], action_scope, bytes32(did_id))
1139
+
1140
+ await self.generate_signed_transaction(
1141
+ [uint64(nft_coin_info.coin.amount)],
1142
+ puzzle_hashes_to_sign,
1143
+ action_scope,
1144
+ fee,
1145
+ {nft_coin_info.coin},
1146
+ new_owner=did_id,
1147
+ new_did_inner_hash=did_inner_hash,
1148
+ extra_conditions=extra_conditions,
1149
+ )
1150
+
1151
+ await self.update_coin_status(nft_coin_info.coin.name(), True)
1152
+ self.wallet_state_manager.state_changed("nft_coin_did_set", self.wallet_info.id)
1153
+
1154
+ async def mint_from_did(
1155
+ self,
1156
+ metadata_list: list[dict[str, Any]],
1157
+ action_scope: WalletActionScope,
1158
+ target_list: Optional[list[bytes32]] = [],
1159
+ mint_number_start: Optional[int] = 1,
1160
+ mint_total: Optional[int] = None,
1161
+ xch_coins: Optional[set[Coin]] = None,
1162
+ xch_change_ph: Optional[bytes32] = None,
1163
+ new_innerpuzhash: Optional[bytes32] = None,
1164
+ new_p2_puzhash: Optional[bytes32] = None,
1165
+ did_coin: Optional[Coin] = None,
1166
+ did_lineage_parent: Optional[bytes32] = None,
1167
+ fee: Optional[uint64] = uint64(0),
1168
+ extra_conditions: tuple[Condition, ...] = tuple(),
1169
+ ) -> None:
1170
+ """
1171
+ Minting NFTs from the DID linked wallet, also used for bulk minting NFTs.
1172
+ - The DID is spent along with an intermediate launcher puzzle which
1173
+ generates a set of ephemeral coins with unique IDs by currying in the
1174
+ mint_number and mint_total for each NFT being minted. These
1175
+ intermediate coins then create the launcher coins for the list of NFTs
1176
+ - The launcher coins are then spent along with the created eve spend
1177
+ and an xch spend that funds the transactions and pays fees.
1178
+ - There is also an option to pass in a list of target puzzlehashes. If
1179
+ provided this method will create an additional transaction transfering
1180
+ the minted NFTs to the row-matched target.
1181
+ :param metadata_list: A list of dicts containing the metadata for each NFT to be minted
1182
+ :param target_list: [Optional] a list of targets for transfering minted NFTs (aka airdrop)
1183
+ :param mint_number_start: [Optional] The starting point for mint number used in intermediate launcher
1184
+ puzzle. Default: 1
1185
+ :param mint_total: [Optional] The total number of NFTs being minted
1186
+ :param xch_coins: [Optional] For use with bulk minting to provide the coin used for funding the minting spend.
1187
+ This coin can be one that will be created in the future
1188
+ :param xch_change_ph: [Optional] For use with bulk minting, so we can specify the puzzle hash that the change
1189
+ from the funding transaction goes to.
1190
+ :param new_innerpuzhash: [Optional] The new inner puzzle hash for the DID once it is spent. For bulk minting we
1191
+ generally don't provide this as the default behaviour is to re-use the existing inner puzzle hash
1192
+ :param new_p2_puzhash: [Optional] The new p2 puzzle hash for the DID once it is spent. For bulk minting we
1193
+ generally don't provide this as the default behaviour is to re-use the existing inner puzzle hash
1194
+ :param did_coin: [Optional] The did coin to use for minting. Required for bulk minting when the DID coin will
1195
+ be created in the future
1196
+ :param did_lineage_parent: [Optional] The parent coin to use for the lineage proof in the DID spend. Needed
1197
+ for bulk minting when the coin will be created in the future
1198
+ :param fee: A fee amount, taken out of the xch spend.
1199
+ """
1200
+ # get DID Wallet
1201
+ for wallet in self.wallet_state_manager.wallets.values():
1202
+ if wallet.type() == WalletType.DECENTRALIZED_ID:
1203
+ if self.get_did() == bytes32.from_hexstr(wallet.get_my_DID()):
1204
+ did_wallet = wallet
1205
+ break
1206
+ else:
1207
+ raise ValueError("There is no DID associated with this NFT wallet")
1208
+
1209
+ assert did_wallet.did_info.current_inner is not None
1210
+ assert did_wallet.did_info.origin_coin is not None
1211
+
1212
+ # Ensure we have an mint_total value
1213
+ if mint_total is None:
1214
+ mint_total = len(metadata_list)
1215
+ assert isinstance(mint_number_start, int)
1216
+ assert len(metadata_list) <= mint_total + 1 - mint_number_start
1217
+
1218
+ # Ensure we have a did coin and its next inner puzzle hash
1219
+ if did_coin is None:
1220
+ did_coin = await did_wallet.get_coin()
1221
+ innerpuz: Program = did_wallet.did_info.current_inner
1222
+ if new_innerpuzhash is None:
1223
+ new_innerpuzhash = innerpuz.get_tree_hash()
1224
+ uncurried_did = did_wallet_puzzles.uncurry_innerpuz(innerpuz)
1225
+ assert uncurried_did is not None
1226
+ p2_puzzle = uncurried_did[0]
1227
+ new_p2_puzhash = p2_puzzle.get_tree_hash()
1228
+ assert new_p2_puzhash is not None
1229
+ # make the primaries for the DID spend
1230
+ primaries = [Payment(new_innerpuzhash, uint64(did_coin.amount), [bytes(new_p2_puzhash)])]
1231
+
1232
+ # Ensure we have an xch coin of high enough amount
1233
+ assert isinstance(fee, uint64)
1234
+ total_amount = len(metadata_list) + fee
1235
+ if xch_coins is None:
1236
+ xch_coins = await self.standard_wallet.select_coins(uint64(total_amount), action_scope)
1237
+ assert len(xch_coins) > 0
1238
+
1239
+ # set the chunk size for the spend bundle we're going to create
1240
+ chunk_size = len(metadata_list)
1241
+
1242
+ # Because bulk minting may not mint all the NFTs in one bundle, we
1243
+ # calculate the edition numbers that will be used in the intermediate
1244
+ # puzzle based on the starting edition number given, and the size of the
1245
+ # chunk going into this spend bundle
1246
+ mint_number_end = mint_number_start + chunk_size
1247
+
1248
+ # Empty set to load with the announcements we will assert from DID to
1249
+ # match the announcements from the intermediate launcher puzzle
1250
+ did_announcements: set[Any] = set()
1251
+ puzzle_assertions: set[Any] = set()
1252
+ amount = uint64(1)
1253
+ intermediate_coin_spends = []
1254
+ launcher_spends = []
1255
+ launcher_ids = []
1256
+ p2_inner_puzzle = await self.standard_wallet.get_new_puzzle()
1257
+ p2_inner_ph = p2_inner_puzzle.get_tree_hash()
1258
+
1259
+ # Loop to create each intermediate coin, launcher, eve and (optional) transfer spends
1260
+ for mint_number in range(mint_number_start, mint_number_end):
1261
+ # Create the puzzle, solution and coin spend for the intermediate launcher
1262
+ intermediate_launcher_puz = did_wallet_puzzles.INTERMEDIATE_LAUNCHER_MOD.curry(
1263
+ chia.wallet.singleton.SINGLETON_LAUNCHER_PUZZLE_HASH, mint_number, mint_total
1264
+ )
1265
+ intermediate_launcher_ph = intermediate_launcher_puz.get_tree_hash()
1266
+ primaries.append(Payment(intermediate_launcher_ph, uint64(0), [intermediate_launcher_ph]))
1267
+ intermediate_launcher_sol = Program.to([])
1268
+ intermediate_launcher_coin = Coin(did_coin.name(), intermediate_launcher_ph, uint64(0))
1269
+ intermediate_launcher_coin_spend = make_spend(
1270
+ intermediate_launcher_coin, intermediate_launcher_puz, intermediate_launcher_sol
1271
+ )
1272
+ intermediate_coin_spends.append(intermediate_launcher_coin_spend)
1273
+
1274
+ # create an ASSERT_COIN_ANNOUNCEMENT for the DID spend. The
1275
+ # intermediate launcher coin issues a CREATE_COIN_ANNOUNCEMENT of
1276
+ # the mint_number and mint_total for the launcher coin it creates
1277
+ intermediate_announcement_message = std_hash(int_to_bytes(mint_number) + int_to_bytes(mint_total))
1278
+ did_announcements.add(std_hash(intermediate_launcher_coin.name() + intermediate_announcement_message))
1279
+
1280
+ # Create the launcher coin, and add its id to a list to be asserted in the DID spend
1281
+ launcher_coin = Coin(
1282
+ intermediate_launcher_coin.name(), chia.wallet.singleton.SINGLETON_LAUNCHER_PUZZLE_HASH, amount
1283
+ )
1284
+ launcher_ids.append(launcher_coin.name())
1285
+
1286
+ # Grab the metadata from metadata_list. The index for metadata_list
1287
+ # needs to be offset by mint_number_start
1288
+ metadata = metadata_list[mint_number - mint_number_start]
1289
+
1290
+ # Create the inner and full puzzles for the eve spend
1291
+ inner_puzzle = create_ownership_layer_puzzle(
1292
+ launcher_coin.name(),
1293
+ b"",
1294
+ p2_inner_puzzle,
1295
+ metadata["royalty_pc"],
1296
+ royalty_puzzle_hash=metadata["royalty_ph"],
1297
+ )
1298
+ eve_fullpuz = nft_puzzles.create_full_puzzle(
1299
+ launcher_coin.name(), metadata["program"], NFT_METADATA_UPDATER.get_tree_hash(), inner_puzzle
1300
+ )
1301
+
1302
+ # Annnouncements for eve spend. These are asserted by the DID spend
1303
+ announcement_message = Program.to([eve_fullpuz.get_tree_hash(), amount, []]).get_tree_hash()
1304
+ did_announcements.add(std_hash(launcher_coin.name() + announcement_message))
1305
+
1306
+ genesis_launcher_solution = Program.to([eve_fullpuz.get_tree_hash(), amount, []])
1307
+
1308
+ launcher_cs = make_spend(
1309
+ launcher_coin, chia.wallet.singleton.SINGLETON_LAUNCHER_PUZZLE, genesis_launcher_solution
1310
+ )
1311
+ launcher_spends.append(launcher_cs)
1312
+
1313
+ eve_coin = Coin(launcher_coin.name(), eve_fullpuz.get_tree_hash(), uint64(amount))
1314
+
1315
+ # To make the eve transaction we need to construct the NFTCoinInfo
1316
+ # for the NFT (which doesn't exist yet)
1317
+ nft_coin = NFTCoinInfo(
1318
+ nft_id=launcher_coin.name(),
1319
+ coin=eve_coin,
1320
+ lineage_proof=LineageProof(
1321
+ parent_name=launcher_coin.parent_coin_info, amount=uint64(launcher_coin.amount)
1322
+ ),
1323
+ full_puzzle=eve_fullpuz,
1324
+ mint_height=uint32(0),
1325
+ )
1326
+
1327
+ # Create the eve transaction setting the DID owner, and applying
1328
+ # the announcements from announcement_set to match the launcher
1329
+ # coin annnouncement
1330
+ if target_list:
1331
+ target_ph = target_list[mint_number - mint_number_start]
1332
+ else:
1333
+ target_ph = p2_inner_ph
1334
+ async with self.wallet_state_manager.new_action_scope(
1335
+ action_scope.config.tx_config, push=False
1336
+ ) as inner_action_scope:
1337
+ await self.generate_signed_transaction(
1338
+ [uint64(eve_coin.amount)],
1339
+ [target_ph],
1340
+ inner_action_scope,
1341
+ nft_coin=nft_coin,
1342
+ new_owner=b"",
1343
+ new_did_inner_hash=b"",
1344
+ additional_bundles=[],
1345
+ memos=[[target_ph]],
1346
+ )
1347
+
1348
+ async with action_scope.use() as interface:
1349
+ interface.side_effects.transactions.extend(inner_action_scope.side_effects.transactions)
1350
+
1351
+ eve_sb = next(
1352
+ tx.spend_bundle for tx in inner_action_scope.side_effects.transactions if tx.spend_bundle is not None
1353
+ )
1354
+ # Extract Puzzle Announcement from eve spend
1355
+ eve_sol = eve_sb.coin_spends[0].solution.to_program()
1356
+ conds = eve_fullpuz.run(eve_sol)
1357
+ eve_puzzle_announcement = next(x for x in conds.as_python() if int_from_bytes(x[0]) == 62)[1]
1358
+ assertion = std_hash(eve_fullpuz.get_tree_hash() + eve_puzzle_announcement)
1359
+ puzzle_assertions.add(assertion)
1360
+
1361
+ # We've now created all the intermediate, launcher, eve and transfer spends.
1362
+ # Create the xch spend to fund the minting.
1363
+ spend_value = sum(coin.amount for coin in xch_coins)
1364
+ change: uint64 = uint64(spend_value - total_amount)
1365
+ if xch_change_ph is None:
1366
+ xch_change_ph = await self.standard_wallet.get_new_puzzlehash()
1367
+ xch_payment = Payment(xch_change_ph, change, [xch_change_ph])
1368
+
1369
+ xch_coins_iter = iter(xch_coins)
1370
+ xch_coin = next(xch_coins_iter)
1371
+
1372
+ message_list: list[bytes32] = [c.name() for c in xch_coins]
1373
+ message_list.append(Coin(xch_coin.name(), xch_payment.puzzle_hash, xch_payment.amount).name())
1374
+ message: bytes32 = std_hash(b"".join(message_list))
1375
+
1376
+ xch_extra_conditions: tuple[Condition, ...] = (
1377
+ AssertCoinAnnouncement(asserted_id=did_coin.name(), asserted_msg=message),
1378
+ )
1379
+ if len(xch_coins) > 1:
1380
+ xch_extra_conditions += (CreateCoinAnnouncement(message),)
1381
+
1382
+ solution: Program = self.standard_wallet.make_solution(
1383
+ primaries=[xch_payment],
1384
+ fee=fee,
1385
+ conditions=xch_extra_conditions,
1386
+ )
1387
+ primary_announcement_hash = AssertCoinAnnouncement(asserted_id=xch_coin.name(), asserted_msg=message).msg_calc
1388
+ # connect this coin assertion to the DID announcement
1389
+ did_coin_announcement = CreateCoinAnnouncement(message)
1390
+ puzzle = await self.standard_wallet.puzzle_for_puzzle_hash(xch_coin.puzzle_hash)
1391
+ xch_spends = [make_spend(xch_coin, puzzle, solution)]
1392
+
1393
+ for xch_coin in xch_coins_iter:
1394
+ puzzle = await self.standard_wallet.puzzle_for_puzzle_hash(xch_coin.puzzle_hash)
1395
+ solution = self.standard_wallet.make_solution(
1396
+ primaries=[], conditions=(AssertCoinAnnouncement(primary_announcement_hash),)
1397
+ )
1398
+ xch_spends.append(make_spend(xch_coin, puzzle, solution))
1399
+ xch_spend = WalletSpendBundle(xch_spends, G2Element())
1400
+
1401
+ # Create the DID spend using the announcements collected when making the intermediate launcher coins
1402
+ did_p2_solution = self.standard_wallet.make_solution(
1403
+ primaries=primaries,
1404
+ conditions=(
1405
+ *extra_conditions,
1406
+ did_coin_announcement,
1407
+ *(AssertCoinAnnouncement(ann) for ann in did_announcements),
1408
+ *(AssertPuzzleAnnouncement(ann) for ann in puzzle_assertions),
1409
+ ),
1410
+ )
1411
+ did_inner_sol: Program = Program.to([1, did_p2_solution])
1412
+ did_full_puzzle: Program = chia.wallet.singleton.create_singleton_puzzle(
1413
+ innerpuz,
1414
+ did_wallet.did_info.origin_coin.name(),
1415
+ )
1416
+ # The DID lineage parent won't not exist if we're bulk minting from a future DID coin
1417
+ if did_lineage_parent:
1418
+ did_parent_info: Optional[LineageProof] = LineageProof(
1419
+ parent_name=did_lineage_parent,
1420
+ inner_puzzle_hash=innerpuz.get_tree_hash(),
1421
+ amount=uint64(did_coin.amount),
1422
+ )
1423
+ else:
1424
+ did_parent_info = did_wallet.get_parent_for_coin(did_coin)
1425
+ assert did_parent_info is not None
1426
+
1427
+ did_full_sol = Program.to(
1428
+ [
1429
+ [
1430
+ did_parent_info.parent_name,
1431
+ did_parent_info.inner_puzzle_hash,
1432
+ did_parent_info.amount,
1433
+ ],
1434
+ did_coin.amount,
1435
+ did_inner_sol,
1436
+ ]
1437
+ )
1438
+ did_spend = make_spend(did_coin, did_full_puzzle, did_full_sol)
1439
+
1440
+ # Collect up all the coin spends and sign them
1441
+ list_of_coinspends = [did_spend, *intermediate_coin_spends, *launcher_spends, *xch_spend.coin_spends]
1442
+ unsigned_spend_bundle = WalletSpendBundle(list_of_coinspends, G2Element())
1443
+
1444
+ # Aggregate everything into a single spend bundle
1445
+ async with action_scope.use() as interface:
1446
+ # This should not be looked to for best practice. I think many of the spends generated above could call
1447
+ # wallet methods that generate transactions and prevent most of the need for this. Refactoring this function
1448
+ # is out of scope so for now we're using this hack.
1449
+ if interface.side_effects.transactions[0].spend_bundle is None:
1450
+ new_spend = unsigned_spend_bundle
1451
+ else:
1452
+ new_spend = WalletSpendBundle.aggregate(
1453
+ [interface.side_effects.transactions[0].spend_bundle, unsigned_spend_bundle]
1454
+ )
1455
+ interface.side_effects.transactions[0] = dataclasses.replace(
1456
+ interface.side_effects.transactions[0], spend_bundle=new_spend, name=new_spend.name()
1457
+ )
1458
+
1459
+ async def mint_from_xch(
1460
+ self,
1461
+ metadata_list: list[dict[str, Any]],
1462
+ action_scope: WalletActionScope,
1463
+ target_list: Optional[list[bytes32]] = [],
1464
+ mint_number_start: Optional[int] = 1,
1465
+ mint_total: Optional[int] = None,
1466
+ xch_coins: Optional[set[Coin]] = None,
1467
+ xch_change_ph: Optional[bytes32] = None,
1468
+ fee: Optional[uint64] = uint64(0),
1469
+ extra_conditions: tuple[Condition, ...] = tuple(),
1470
+ ) -> None:
1471
+ """
1472
+ Minting NFTs from a single XCH spend using intermediate launcher puzzle
1473
+ :param metadata_list: A list of dicts containing the metadata for each NFT to be minted
1474
+ :param target_list: [Optional] a list of targets for transfering minted NFTs (aka airdrop)
1475
+ :param mint_number_start: [Optional] The starting point for mint number used in intermediate launcher
1476
+ puzzle. Default: 1
1477
+ :param mint_total: [Optional] The total number of NFTs being minted
1478
+ :param xch_coins: [Optional] For use with bulk minting to provide the coin used for funding the minting spend.
1479
+ This coin can be one that will be created in the future
1480
+ :param xch_change_ph: [Optional] For use with bulk minting, so we can specify the puzzle hash that the change
1481
+ from the funding transaction goes to.
1482
+ :param fee: A fee amount, taken out of the xch spend.
1483
+ """
1484
+
1485
+ # Ensure we have an mint_total value
1486
+ if mint_total is None:
1487
+ mint_total = len(metadata_list)
1488
+ assert isinstance(mint_number_start, int)
1489
+ assert len(metadata_list) <= mint_total + 1 - mint_number_start
1490
+
1491
+ # Ensure we have an xch coin of high enough amount
1492
+ assert isinstance(fee, uint64)
1493
+ total_amount = len(metadata_list) + fee
1494
+ if xch_coins is None:
1495
+ xch_coins = await self.standard_wallet.select_coins(uint64(total_amount), action_scope)
1496
+ assert len(xch_coins) > 0
1497
+
1498
+ funding_coin = xch_coins.copy().pop()
1499
+
1500
+ # set the chunk size for the spend bundle we're going to create
1501
+ chunk_size = len(metadata_list)
1502
+
1503
+ # Because bulk minting may not mint all the NFTs in one bundle, we
1504
+ # calculate the edition numbers that will be used in the intermediate
1505
+ # puzzle based on the starting edition number given, and the size of the
1506
+ # chunk going into this spend bundle
1507
+ mint_number_end = mint_number_start + chunk_size
1508
+
1509
+ # Empty set to load with the announcements we will assert from XCH to
1510
+ # match the announcements from the intermediate launcher puzzle
1511
+ coin_announcements: set[bytes32] = set()
1512
+ puzzle_assertions: set[bytes32] = set()
1513
+ primaries = []
1514
+ amount = uint64(1)
1515
+ intermediate_coin_spends = []
1516
+ launcher_spends = []
1517
+ launcher_ids = []
1518
+ p2_inner_puzzle = await self.standard_wallet.get_new_puzzle()
1519
+ p2_inner_ph = p2_inner_puzzle.get_tree_hash()
1520
+
1521
+ # Loop to create each intermediate coin, launcher, eve and (optional) transfer spends
1522
+ for mint_number in range(mint_number_start, mint_number_end):
1523
+ # Create the puzzle, solution and coin spend for the intermediate launcher
1524
+ intermediate_launcher_puz = nft_puzzles.INTERMEDIATE_LAUNCHER_MOD.curry(
1525
+ nft_puzzles.LAUNCHER_PUZZLE_HASH, mint_number, mint_total
1526
+ )
1527
+ intermediate_launcher_ph = intermediate_launcher_puz.get_tree_hash()
1528
+ primaries.append(Payment(intermediate_launcher_ph, uint64(1), [intermediate_launcher_ph]))
1529
+ intermediate_launcher_sol = Program.to([])
1530
+ intermediate_launcher_coin = Coin(funding_coin.name(), intermediate_launcher_ph, uint64(1))
1531
+ intermediate_launcher_coin_spend = make_spend(
1532
+ intermediate_launcher_coin, intermediate_launcher_puz, intermediate_launcher_sol
1533
+ )
1534
+ intermediate_coin_spends.append(intermediate_launcher_coin_spend)
1535
+
1536
+ # create an ASSERT_COIN_ANNOUNCEMENT for the XCH spend. The
1537
+ # intermediate launcher coin issues a CREATE_COIN_ANNOUNCEMENT of
1538
+ # the mint_number and mint_total for the launcher coin it creates
1539
+ intermediate_announcement_message = std_hash(int_to_bytes(mint_number) + int_to_bytes(mint_total))
1540
+ coin_announcements.add(std_hash(intermediate_launcher_coin.name() + intermediate_announcement_message))
1541
+
1542
+ # Create the launcher coin, and add its id to a list to be asserted in the XCH spend
1543
+ launcher_coin = Coin(intermediate_launcher_coin.name(), nft_puzzles.LAUNCHER_PUZZLE_HASH, amount)
1544
+ launcher_ids.append(launcher_coin.name())
1545
+
1546
+ # Grab the metadata from metadata_list. The index for metadata_list
1547
+ # needs to be offset by mint_number_start, and since
1548
+ # mint_number starts at 1 not 0, we also subtract 1.
1549
+ metadata = metadata_list[mint_number - mint_number_start]
1550
+
1551
+ # Create the inner and full puzzles for the eve spend
1552
+ inner_puzzle = create_ownership_layer_puzzle(
1553
+ launcher_coin.name(),
1554
+ b"",
1555
+ p2_inner_puzzle,
1556
+ metadata["royalty_pc"],
1557
+ royalty_puzzle_hash=metadata["royalty_ph"],
1558
+ )
1559
+ eve_fullpuz = nft_puzzles.create_full_puzzle(
1560
+ launcher_coin.name(), metadata["program"], NFT_METADATA_UPDATER.get_tree_hash(), inner_puzzle
1561
+ )
1562
+
1563
+ # Annnouncements for eve spend. These are asserted by the xch spend
1564
+ announcement_message = Program.to([eve_fullpuz.get_tree_hash(), amount, []]).get_tree_hash()
1565
+ coin_announcements.add(std_hash(launcher_coin.name() + announcement_message))
1566
+
1567
+ genesis_launcher_solution = Program.to([eve_fullpuz.get_tree_hash(), amount, []])
1568
+
1569
+ launcher_cs = make_spend(launcher_coin, nft_puzzles.LAUNCHER_PUZZLE, genesis_launcher_solution)
1570
+ launcher_spends.append(launcher_cs)
1571
+
1572
+ eve_coin = Coin(launcher_coin.name(), eve_fullpuz.get_tree_hash(), uint64(amount))
1573
+
1574
+ # To make the eve transaction we need to construct the NFTCoinInfo
1575
+ # for the NFT (which doesn't exist yet)
1576
+ nft_coin = NFTCoinInfo(
1577
+ nft_id=launcher_coin.name(),
1578
+ coin=eve_coin,
1579
+ lineage_proof=LineageProof(
1580
+ parent_name=launcher_coin.parent_coin_info, amount=uint64(launcher_coin.amount)
1581
+ ),
1582
+ full_puzzle=eve_fullpuz,
1583
+ mint_height=uint32(0),
1584
+ )
1585
+
1586
+ # Create the eve transaction with targets if present
1587
+ if target_list:
1588
+ target_ph = target_list[mint_number - mint_number_start]
1589
+ else:
1590
+ target_ph = p2_inner_ph
1591
+ async with self.wallet_state_manager.new_action_scope(
1592
+ action_scope.config.tx_config, push=False
1593
+ ) as inner_action_scope:
1594
+ await self.generate_signed_transaction(
1595
+ [uint64(eve_coin.amount)],
1596
+ [target_ph],
1597
+ inner_action_scope,
1598
+ nft_coin=nft_coin,
1599
+ new_owner=b"",
1600
+ new_did_inner_hash=b"",
1601
+ additional_bundles=[],
1602
+ memos=[[target_ph]],
1603
+ )
1604
+
1605
+ async with action_scope.use() as interface:
1606
+ interface.side_effects.transactions.extend(inner_action_scope.side_effects.transactions)
1607
+
1608
+ eve_sb = next(
1609
+ tx.spend_bundle for tx in inner_action_scope.side_effects.transactions if tx.spend_bundle is not None
1610
+ )
1611
+ # Extract Puzzle Announcement from eve spend
1612
+ eve_sol = eve_sb.coin_spends[0].solution.to_program()
1613
+ conds = eve_fullpuz.run(eve_sol)
1614
+ eve_puzzle_announcement = next(x for x in conds.as_python() if int_from_bytes(x[0]) == 62)[1]
1615
+ assertion = std_hash(eve_fullpuz.get_tree_hash() + eve_puzzle_announcement)
1616
+ puzzle_assertions.add(assertion)
1617
+
1618
+ # We've now created all the intermediate, launcher, eve and transfer spends.
1619
+ # Create the xch spend to fund the minting.
1620
+ spend_value = sum(coin.amount for coin in xch_coins)
1621
+ change: uint64 = uint64(spend_value - total_amount)
1622
+ xch_spends = []
1623
+ if xch_change_ph is None:
1624
+ xch_change_ph = await self.standard_wallet.get_new_puzzlehash()
1625
+ xch_payment = Payment(xch_change_ph, change, [xch_change_ph])
1626
+
1627
+ first = True
1628
+ for xch_coin in xch_coins:
1629
+ puzzle: Program = await self.standard_wallet.puzzle_for_puzzle_hash(xch_coin.puzzle_hash)
1630
+ if first:
1631
+ message_list: list[bytes32] = [c.name() for c in xch_coins]
1632
+ message_list.append(Coin(xch_coin.name(), xch_payment.puzzle_hash, xch_payment.amount).name())
1633
+ message: bytes32 = std_hash(b"".join(message_list))
1634
+
1635
+ if len(xch_coins) > 1:
1636
+ extra_conditions += (CreateCoinAnnouncement(message),)
1637
+ extra_conditions += tuple(AssertCoinAnnouncement(ann) for ann in coin_announcements)
1638
+ extra_conditions += tuple(AssertPuzzleAnnouncement(ann) for ann in puzzle_assertions)
1639
+
1640
+ solution: Program = self.standard_wallet.make_solution(
1641
+ primaries=[xch_payment, *primaries],
1642
+ fee=fee,
1643
+ conditions=extra_conditions,
1644
+ )
1645
+ primary_announcement = AssertCoinAnnouncement(asserted_id=xch_coin.name(), asserted_msg=message)
1646
+ first = False
1647
+ else:
1648
+ solution = self.standard_wallet.make_solution(primaries=[], conditions=(primary_announcement,))
1649
+ xch_spends.append(make_spend(xch_coin, puzzle, solution))
1650
+
1651
+ # Collect up all the coin spends and sign them
1652
+ list_of_coinspends = intermediate_coin_spends + launcher_spends + xch_spends
1653
+ unsigned_spend_bundle = WalletSpendBundle(list_of_coinspends, G2Element())
1654
+
1655
+ # Aggregate everything into a single spend bundle
1656
+ async with action_scope.use() as interface:
1657
+ # This should not be looked to for best practice. I think many of the spends generated above could call
1658
+ # wallet methods that generate transactions and prevent most of the need for this. Refactoring this function
1659
+ # is out of scope so for now we're using this hack.
1660
+ if interface.side_effects.transactions[0].spend_bundle is None:
1661
+ new_spend = unsigned_spend_bundle
1662
+ else:
1663
+ new_spend = WalletSpendBundle.aggregate(
1664
+ [interface.side_effects.transactions[0].spend_bundle, unsigned_spend_bundle]
1665
+ )
1666
+ interface.side_effects.transactions[0] = dataclasses.replace(
1667
+ interface.side_effects.transactions[0], spend_bundle=new_spend, name=new_spend.name()
1668
+ )
1669
+
1670
+ async def select_coins(
1671
+ self,
1672
+ amount: uint64,
1673
+ action_scope: WalletActionScope,
1674
+ ) -> set[Coin]:
1675
+ raise RuntimeError("NFTWallet does not support select_coins()")
1676
+
1677
+ def require_derivation_paths(self) -> bool:
1678
+ return False
1679
+
1680
+ def puzzle_hash_for_pk(self, pubkey: G1Element) -> bytes32:
1681
+ raise RuntimeError("NFTWallet does not support puzzle_hash_for_pk")
1682
+
1683
+ def get_name(self) -> str:
1684
+ return self.wallet_info.name
1685
+
1686
+ async def match_hinted_coin(self, coin: Coin, hint: bytes32) -> bool:
1687
+ return False