chia-blockchain 2.4.4__py3-none-any.whl

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